Commit 5a7bb3474eb10ec9dea8409466a14f72ead73e60
1 parent
59531166
generate_auto_job: generate overloaded config decls for optional
For optional parameter/choices, generate an overloaded config method that takes no arguments. This makes it possible to convert from a bare argument to one that takes an optional parameter without breaking binary compatibility.
Showing
5 changed files
with
55 additions
and
22 deletions
generate_auto_job
| @@ -302,22 +302,25 @@ class Main: | @@ -302,22 +302,25 @@ class Main: | ||
| 302 | 302 | ||
| 303 | def handle_trivial(self, i, identifier, cfg, prefix, kind, v): | 303 | def handle_trivial(self, i, identifier, cfg, prefix, kind, v): |
| 304 | decl_arg = 1 | 304 | decl_arg = 1 |
| 305 | + decl_arg_optional = False | ||
| 305 | if kind == 'bare': | 306 | if kind == 'bare': |
| 306 | decl_arg = 0 | 307 | decl_arg = 0 |
| 307 | self.init.append(f'this->ap.addBare("{i}", ' | 308 | self.init.append(f'this->ap.addBare("{i}", ' |
| 308 | f'[this](){{{cfg}->{identifier}();}});') | 309 | f'[this](){{{cfg}->{identifier}();}});') |
| 309 | - elif kind == 'optional_parameter': | ||
| 310 | - self.init.append(f'this->ap.addOptionalParameter("{i}", ' | ||
| 311 | - f'[this](char *x){{{cfg}->{identifier}(x);}});') | ||
| 312 | elif kind == 'required_parameter': | 310 | elif kind == 'required_parameter': |
| 313 | self.init.append(f'this->ap.addRequiredParameter("{i}", ' | 311 | self.init.append(f'this->ap.addRequiredParameter("{i}", ' |
| 314 | f'[this](char *x){{{cfg}->{identifier}(x);}}' | 312 | f'[this](char *x){{{cfg}->{identifier}(x);}}' |
| 315 | f', "{v}");') | 313 | f', "{v}");') |
| 314 | + elif kind == 'optional_parameter': | ||
| 315 | + decl_arg_optional = True | ||
| 316 | + self.init.append(f'this->ap.addOptionalParameter("{i}", ' | ||
| 317 | + f'[this](char *x){{{cfg}->{identifier}(x);}});') | ||
| 316 | elif kind == 'required_choices': | 318 | elif kind == 'required_choices': |
| 317 | self.init.append(f'this->ap.addChoices("{i}", ' | 319 | self.init.append(f'this->ap.addChoices("{i}", ' |
| 318 | f'[this](char *x){{{cfg}->{identifier}(x);}}' | 320 | f'[this](char *x){{{cfg}->{identifier}(x);}}' |
| 319 | f', true, {v}_choices);') | 321 | f', true, {v}_choices);') |
| 320 | elif kind == 'optional_choices': | 322 | elif kind == 'optional_choices': |
| 323 | + decl_arg_optional = True | ||
| 321 | self.init.append(f'this->ap.addChoices("{i}", ' | 324 | self.init.append(f'this->ap.addChoices("{i}", ' |
| 322 | f'[this](char *x){{{cfg}->{identifier}(x);}}' | 325 | f'[this](char *x){{{cfg}->{identifier}(x);}}' |
| 323 | f', false, {v}_choices);') | 326 | f', false, {v}_choices);') |
| @@ -332,21 +335,30 @@ class Main: | @@ -332,21 +335,30 @@ class Main: | ||
| 332 | if fn not in self.declared_configs: | 335 | if fn not in self.declared_configs: |
| 333 | self.declared_configs.add(fn) | 336 | self.declared_configs.add(fn) |
| 334 | self.config_decls[cfg].append(f'QPDF_DLL {fn};') | 337 | self.config_decls[cfg].append(f'QPDF_DLL {fn};') |
| 338 | + if decl_arg_optional: | ||
| 339 | + # Rather than making the parameter optional, add an | ||
| 340 | + # overloaded method that takes no arguments. This | ||
| 341 | + # strategy enables us to change an option from bare to | ||
| 342 | + # optional_parameter or optional_choices without | ||
| 343 | + # breaking binary compatibility. The overloaded | ||
| 344 | + # methods both have to be implemented manually. | ||
| 345 | + self.config_decls[cfg].append( | ||
| 346 | + f'QPDF_DLL {config_prefix}* {identifier}();') | ||
| 335 | 347 | ||
| 336 | def handle_flag(self, i, identifier, kind, v): | 348 | def handle_flag(self, i, identifier, kind, v): |
| 337 | if kind == 'bare': | 349 | if kind == 'bare': |
| 338 | self.decls.append(f'void {identifier}();') | 350 | self.decls.append(f'void {identifier}();') |
| 339 | self.init.append(f'this->ap.addBare("{i}", ' | 351 | self.init.append(f'this->ap.addBare("{i}", ' |
| 340 | f'b(&ArgParser::{identifier}));') | 352 | f'b(&ArgParser::{identifier}));') |
| 341 | - elif kind == 'optional_parameter': | ||
| 342 | - self.decls.append(f'void {identifier}(char *);') | ||
| 343 | - self.init.append(f'this->ap.addOptionalParameter("{i}", ' | ||
| 344 | - f'p(&ArgParser::{identifier}));') | ||
| 345 | elif kind == 'required_parameter': | 353 | elif kind == 'required_parameter': |
| 346 | self.decls.append(f'void {identifier}(char *);') | 354 | self.decls.append(f'void {identifier}(char *);') |
| 347 | self.init.append(f'this->ap.addRequiredParameter("{i}", ' | 355 | self.init.append(f'this->ap.addRequiredParameter("{i}", ' |
| 348 | f'p(&ArgParser::{identifier})' | 356 | f'p(&ArgParser::{identifier})' |
| 349 | f', "{v}");') | 357 | f', "{v}");') |
| 358 | + elif kind == 'optional_parameter': | ||
| 359 | + self.decls.append(f'void {identifier}(char *);') | ||
| 360 | + self.init.append(f'this->ap.addOptionalParameter("{i}", ' | ||
| 361 | + f'p(&ArgParser::{identifier}));') | ||
| 350 | elif kind == 'required_choices': | 362 | elif kind == 'required_choices': |
| 351 | self.decls.append(f'void {identifier}(char *);') | 363 | self.decls.append(f'void {identifier}(char *);') |
| 352 | self.init.append(f'this->ap.addChoices("{i}", ' | 364 | self.init.append(f'this->ap.addChoices("{i}", ' |
| @@ -429,10 +441,10 @@ class Main: | @@ -429,10 +441,10 @@ class Main: | ||
| 429 | 441 | ||
| 430 | for i in o.get('bare', []): | 442 | for i in o.get('bare', []): |
| 431 | flags[i] = ['bare', None] | 443 | flags[i] = ['bare', None] |
| 432 | - for i in o.get('optional_parameter', []): | ||
| 433 | - flags[i] = ['optional_parameter', None] | ||
| 434 | for i, v in o.get('required_parameter', {}).items(): | 444 | for i, v in o.get('required_parameter', {}).items(): |
| 435 | flags[i] = ['required_parameter', v] | 445 | flags[i] = ['required_parameter', v] |
| 446 | + for i in o.get('optional_parameter', []): | ||
| 447 | + flags[i] = ['optional_parameter', None] | ||
| 436 | for i, v in o.get('required_choices', {}).items(): | 448 | for i, v in o.get('required_choices', {}).items(): |
| 437 | flags[i] = ['required_choices', v] | 449 | flags[i] = ['required_choices', v] |
| 438 | for i, v in o.get('optional_choices', {}).items(): | 450 | for i, v in o.get('optional_choices', {}).items(): |
| @@ -464,21 +476,21 @@ class Main: | @@ -464,21 +476,21 @@ class Main: | ||
| 464 | if kind == 'bare': | 476 | if kind == 'bare': |
| 465 | self.json_init.append( | 477 | self.json_init.append( |
| 466 | f'addBare([this]() {{ {config}->{flag_key}(); }});') | 478 | f'addBare([this]() {{ {config}->{flag_key}(); }});') |
| 467 | - elif kind == 'optional_parameter' or kind == 'required_parameter': | 479 | + elif kind == 'required_parameter' or kind == 'optional_parameter': |
| 468 | # Optional parameters end up just being the empty string, | 480 | # Optional parameters end up just being the empty string, |
| 469 | # so the handler has to deal with it. The empty string is | 481 | # so the handler has to deal with it. The empty string is |
| 470 | # also allowed for non-optional. | 482 | # also allowed for non-optional. |
| 471 | self.json_init.append( | 483 | self.json_init.append( |
| 472 | f'addParameter([this](char const* p)' | 484 | f'addParameter([this](char const* p)' |
| 473 | f' {{ {config}->{flag_key}(p); }});') | 485 | f' {{ {config}->{flag_key}(p); }});') |
| 474 | - elif kind == 'optional_choices': | ||
| 475 | - self.json_init.append( | ||
| 476 | - f'addChoices({v}_choices, false,' | ||
| 477 | - f' [this](char const* p) {{ {config}->{flag_key}(p); }});') | ||
| 478 | elif kind == 'required_choices': | 486 | elif kind == 'required_choices': |
| 479 | self.json_init.append( | 487 | self.json_init.append( |
| 480 | f'addChoices({v}_choices, true,' | 488 | f'addChoices({v}_choices, true,' |
| 481 | f' [this](char const* p) {{ {config}->{flag_key}(p); }});') | 489 | f' [this](char const* p) {{ {config}->{flag_key}(p); }});') |
| 490 | + elif kind == 'optional_choices': | ||
| 491 | + self.json_init.append( | ||
| 492 | + f'addChoices({v}_choices, false,' | ||
| 493 | + f' [this](char const* p) {{ {config}->{flag_key}(p); }});') | ||
| 482 | 494 | ||
| 483 | def handle_json_manual(self, path): | 495 | def handle_json_manual(self, path): |
| 484 | method = re.sub(r'\.([a-zA-Z0-9])', | 496 | method = re.sub(r'\.([a-zA-Z0-9])', |
include/qpdf/auto_job_c_main.hh
| @@ -44,8 +44,6 @@ QPDF_DLL Config* suppressRecovery(); | @@ -44,8 +44,6 @@ QPDF_DLL Config* suppressRecovery(); | ||
| 44 | QPDF_DLL Config* verbose(); | 44 | QPDF_DLL Config* verbose(); |
| 45 | QPDF_DLL Config* warningExit0(); | 45 | QPDF_DLL Config* warningExit0(); |
| 46 | QPDF_DLL Config* withImages(); | 46 | QPDF_DLL Config* withImages(); |
| 47 | -QPDF_DLL Config* collate(char const* parameter); | ||
| 48 | -QPDF_DLL Config* splitPages(char const* parameter); | ||
| 49 | QPDF_DLL Config* compressionLevel(char const* parameter); | 47 | QPDF_DLL Config* compressionLevel(char const* parameter); |
| 50 | QPDF_DLL Config* copyEncryption(char const* parameter); | 48 | QPDF_DLL Config* copyEncryption(char const* parameter); |
| 51 | QPDF_DLL Config* encryptionFilePassword(char const* parameter); | 49 | QPDF_DLL Config* encryptionFilePassword(char const* parameter); |
| @@ -65,6 +63,10 @@ QPDF_DLL Config* removeAttachment(char const* parameter); | @@ -65,6 +63,10 @@ QPDF_DLL Config* removeAttachment(char const* parameter); | ||
| 65 | QPDF_DLL Config* rotate(char const* parameter); | 63 | QPDF_DLL Config* rotate(char const* parameter); |
| 66 | QPDF_DLL Config* showAttachment(char const* parameter); | 64 | QPDF_DLL Config* showAttachment(char const* parameter); |
| 67 | QPDF_DLL Config* showObject(char const* parameter); | 65 | QPDF_DLL Config* showObject(char const* parameter); |
| 66 | +QPDF_DLL Config* collate(char const* parameter); | ||
| 67 | +QPDF_DLL Config* collate(); | ||
| 68 | +QPDF_DLL Config* splitPages(char const* parameter); | ||
| 69 | +QPDF_DLL Config* splitPages(); | ||
| 68 | QPDF_DLL Config* compressStreams(char const* parameter); | 70 | QPDF_DLL Config* compressStreams(char const* parameter); |
| 69 | QPDF_DLL Config* decodeLevel(char const* parameter); | 71 | QPDF_DLL Config* decodeLevel(char const* parameter); |
| 70 | QPDF_DLL Config* flattenAnnotations(char const* parameter); | 72 | QPDF_DLL Config* flattenAnnotations(char const* parameter); |
| @@ -76,3 +78,4 @@ QPDF_DLL Config* passwordMode(char const* parameter); | @@ -76,3 +78,4 @@ QPDF_DLL Config* passwordMode(char const* parameter); | ||
| 76 | QPDF_DLL Config* removeUnreferencedResources(char const* parameter); | 78 | QPDF_DLL Config* removeUnreferencedResources(char const* parameter); |
| 77 | QPDF_DLL Config* streamData(char const* parameter); | 79 | QPDF_DLL Config* streamData(char const* parameter); |
| 78 | QPDF_DLL Config* json(char const* parameter); | 80 | QPDF_DLL Config* json(char const* parameter); |
| 81 | +QPDF_DLL Config* json(); |
job.sums
| 1 | # Generated by generate_auto_job | 1 | # Generated by generate_auto_job |
| 2 | -generate_auto_job cb0945a8aa05eb4a523d0931b2cf1a70188e4667d42e012d7621b3aba4f32621 | 2 | +generate_auto_job 1fdb113412a444aad67b0232f3f6c4f50d9e2a5701691e5146fd1b559039ef2e |
| 3 | include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e | 3 | include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e |
| 4 | include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee | 4 | include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee |
| 5 | include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265 | 5 | include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265 |
| 6 | -include/qpdf/auto_job_c_main.hh ff776dd643279330fbf59770d1abf5aaeb13f20bfc5f6a25997aaa72a0907b44 | 6 | +include/qpdf/auto_job_c_main.hh 69d5ea26098bcb6ec5b5e37ba0bca9e7d16a784d2618e0c05d635046848d5123 |
| 7 | include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 | 7 | include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 |
| 8 | include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50 | 8 | include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50 |
| 9 | job.yml effc93a805fb74503be2213ad885238db21991ba3d084fbfeff01183c66cb002 | 9 | job.yml effc93a805fb74503be2213ad885238db21991ba3d084fbfeff01183c66cb002 |
| 10 | libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6 | 10 | libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6 |
| 11 | libqpdf/qpdf/auto_job_help.hh 6002f503368f319a3d717484ac39d1558f34e67989d442f394791f6f6f5f0500 | 11 | libqpdf/qpdf/auto_job_help.hh 6002f503368f319a3d717484ac39d1558f34e67989d442f394791f6f6f5f0500 |
| 12 | -libqpdf/qpdf/auto_job_init.hh c244e03e8b83ed7db732920f40aff0134e5f2e78a6edb9473ea4dd1934a8953e | 12 | +libqpdf/qpdf/auto_job_init.hh fd13b9f730e6275a39a15d193bd9af19cf37f4495699ec1886c2b208d7811ab1 |
| 13 | libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a357a81f64fe36af2b0cf | 13 | libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a357a81f64fe36af2b0cf |
| 14 | libqpdf/qpdf/auto_job_json_init.hh 3f86ce40931ca8f417d050fcd49104d73c1fa4e977ad19d54b372831a8ea17ed | 14 | libqpdf/qpdf/auto_job_json_init.hh 3f86ce40931ca8f417d050fcd49104d73c1fa4e977ad19d54b372831a8ea17ed |
| 15 | libqpdf/qpdf/auto_job_schema.hh 18a3780671d95224cb9a27dcac627c421cae509d59f33a63e6bda0ab53cce923 | 15 | libqpdf/qpdf/auto_job_schema.hh 18a3780671d95224cb9a27dcac627c421cae509d59f33a63e6bda0ab53cce923 |
libqpdf/QPDFJob_config.cc
| @@ -106,6 +106,12 @@ QPDFJob::Config::coalesceContents() | @@ -106,6 +106,12 @@ QPDFJob::Config::coalesceContents() | ||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | QPDFJob::Config* | 108 | QPDFJob::Config* |
| 109 | +QPDFJob::Config::collate() | ||
| 110 | +{ | ||
| 111 | + return collate(nullptr); | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +QPDFJob::Config* | ||
| 109 | QPDFJob::Config::collate(char const* parameter) | 115 | QPDFJob::Config::collate(char const* parameter) |
| 110 | { | 116 | { |
| 111 | auto n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : | 117 | auto n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : |
| @@ -235,9 +241,15 @@ QPDFJob::Config::isEncrypted() | @@ -235,9 +241,15 @@ QPDFJob::Config::isEncrypted() | ||
| 235 | } | 241 | } |
| 236 | 242 | ||
| 237 | QPDFJob::Config* | 243 | QPDFJob::Config* |
| 244 | +QPDFJob::Config::json() | ||
| 245 | +{ | ||
| 246 | + return json(nullptr); | ||
| 247 | +} | ||
| 248 | + | ||
| 249 | +QPDFJob::Config* | ||
| 238 | QPDFJob::Config::json(char const* parameter) | 250 | QPDFJob::Config::json(char const* parameter) |
| 239 | { | 251 | { |
| 240 | - if (parameter) | 252 | + if (parameter && strlen(parameter)) |
| 241 | { | 253 | { |
| 242 | if (strcmp(parameter, "latest") == 0) | 254 | if (strcmp(parameter, "latest") == 0) |
| 243 | { | 255 | { |
| @@ -517,6 +529,12 @@ QPDFJob::Config::showXref() | @@ -517,6 +529,12 @@ QPDFJob::Config::showXref() | ||
| 517 | } | 529 | } |
| 518 | 530 | ||
| 519 | QPDFJob::Config* | 531 | QPDFJob::Config* |
| 532 | +QPDFJob::Config::splitPages() | ||
| 533 | +{ | ||
| 534 | + return splitPages(nullptr); | ||
| 535 | +} | ||
| 536 | + | ||
| 537 | +QPDFJob::Config* | ||
| 520 | QPDFJob::Config::splitPages(char const* parameter) | 538 | QPDFJob::Config::splitPages(char const* parameter) |
| 521 | { | 539 | { |
| 522 | int n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : | 540 | int n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : |
libqpdf/qpdf/auto_job_init.hh
| @@ -79,8 +79,6 @@ this->ap.addBare("underlay", b(&ArgParser::argUnderlay)); | @@ -79,8 +79,6 @@ this->ap.addBare("underlay", b(&ArgParser::argUnderlay)); | ||
| 79 | this->ap.addBare("verbose", [this](){c_main->verbose();}); | 79 | this->ap.addBare("verbose", [this](){c_main->verbose();}); |
| 80 | this->ap.addBare("warning-exit-0", [this](){c_main->warningExit0();}); | 80 | this->ap.addBare("warning-exit-0", [this](){c_main->warningExit0();}); |
| 81 | this->ap.addBare("with-images", [this](){c_main->withImages();}); | 81 | this->ap.addBare("with-images", [this](){c_main->withImages();}); |
| 82 | -this->ap.addOptionalParameter("collate", [this](char *x){c_main->collate(x);}); | ||
| 83 | -this->ap.addOptionalParameter("split-pages", [this](char *x){c_main->splitPages(x);}); | ||
| 84 | this->ap.addRequiredParameter("compression-level", [this](char *x){c_main->compressionLevel(x);}, "level"); | 82 | this->ap.addRequiredParameter("compression-level", [this](char *x){c_main->compressionLevel(x);}, "level"); |
| 85 | this->ap.addRequiredParameter("copy-encryption", [this](char *x){c_main->copyEncryption(x);}, "file"); | 83 | this->ap.addRequiredParameter("copy-encryption", [this](char *x){c_main->copyEncryption(x);}, "file"); |
| 86 | this->ap.addRequiredParameter("encryption-file-password", [this](char *x){c_main->encryptionFilePassword(x);}, "password"); | 84 | this->ap.addRequiredParameter("encryption-file-password", [this](char *x){c_main->encryptionFilePassword(x);}, "password"); |
| @@ -100,6 +98,8 @@ this->ap.addRequiredParameter("remove-attachment", [this](char *x){c_main->remov | @@ -100,6 +98,8 @@ this->ap.addRequiredParameter("remove-attachment", [this](char *x){c_main->remov | ||
| 100 | this->ap.addRequiredParameter("rotate", [this](char *x){c_main->rotate(x);}, "[+|-]angle"); | 98 | this->ap.addRequiredParameter("rotate", [this](char *x){c_main->rotate(x);}, "[+|-]angle"); |
| 101 | this->ap.addRequiredParameter("show-attachment", [this](char *x){c_main->showAttachment(x);}, "attachment"); | 99 | this->ap.addRequiredParameter("show-attachment", [this](char *x){c_main->showAttachment(x);}, "attachment"); |
| 102 | this->ap.addRequiredParameter("show-object", [this](char *x){c_main->showObject(x);}, "trailer"); | 100 | this->ap.addRequiredParameter("show-object", [this](char *x){c_main->showObject(x);}, "trailer"); |
| 101 | +this->ap.addOptionalParameter("collate", [this](char *x){c_main->collate(x);}); | ||
| 102 | +this->ap.addOptionalParameter("split-pages", [this](char *x){c_main->splitPages(x);}); | ||
| 103 | this->ap.addChoices("compress-streams", [this](char *x){c_main->compressStreams(x);}, true, yn_choices); | 103 | this->ap.addChoices("compress-streams", [this](char *x){c_main->compressStreams(x);}, true, yn_choices); |
| 104 | this->ap.addChoices("decode-level", [this](char *x){c_main->decodeLevel(x);}, true, decode_level_choices); | 104 | this->ap.addChoices("decode-level", [this](char *x){c_main->decodeLevel(x);}, true, decode_level_choices); |
| 105 | this->ap.addChoices("flatten-annotations", [this](char *x){c_main->flattenAnnotations(x);}, true, flatten_choices); | 105 | this->ap.addChoices("flatten-annotations", [this](char *x){c_main->flattenAnnotations(x);}, true, flatten_choices); |