Commit 5a7bb3474eb10ec9dea8409466a14f72ead73e60

Authored by Jay Berkenbilt
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.
generate_auto_job
... ... @@ -302,22 +302,25 @@ class Main:
302 302  
303 303 def handle_trivial(self, i, identifier, cfg, prefix, kind, v):
304 304 decl_arg = 1
  305 + decl_arg_optional = False
305 306 if kind == 'bare':
306 307 decl_arg = 0
307 308 self.init.append(f'this->ap.addBare("{i}", '
308 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 310 elif kind == 'required_parameter':
313 311 self.init.append(f'this->ap.addRequiredParameter("{i}", '
314 312 f'[this](char *x){{{cfg}->{identifier}(x);}}'
315 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 318 elif kind == 'required_choices':
317 319 self.init.append(f'this->ap.addChoices("{i}", '
318 320 f'[this](char *x){{{cfg}->{identifier}(x);}}'
319 321 f', true, {v}_choices);')
320 322 elif kind == 'optional_choices':
  323 + decl_arg_optional = True
321 324 self.init.append(f'this->ap.addChoices("{i}", '
322 325 f'[this](char *x){{{cfg}->{identifier}(x);}}'
323 326 f', false, {v}_choices);')
... ... @@ -332,21 +335,30 @@ class Main:
332 335 if fn not in self.declared_configs:
333 336 self.declared_configs.add(fn)
334 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 348 def handle_flag(self, i, identifier, kind, v):
337 349 if kind == 'bare':
338 350 self.decls.append(f'void {identifier}();')
339 351 self.init.append(f'this->ap.addBare("{i}", '
340 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 353 elif kind == 'required_parameter':
346 354 self.decls.append(f'void {identifier}(char *);')
347 355 self.init.append(f'this->ap.addRequiredParameter("{i}", '
348 356 f'p(&ArgParser::{identifier})'
349 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 362 elif kind == 'required_choices':
351 363 self.decls.append(f'void {identifier}(char *);')
352 364 self.init.append(f'this->ap.addChoices("{i}", '
... ... @@ -429,10 +441,10 @@ class Main:
429 441  
430 442 for i in o.get('bare', []):
431 443 flags[i] = ['bare', None]
432   - for i in o.get('optional_parameter', []):
433   - flags[i] = ['optional_parameter', None]
434 444 for i, v in o.get('required_parameter', {}).items():
435 445 flags[i] = ['required_parameter', v]
  446 + for i in o.get('optional_parameter', []):
  447 + flags[i] = ['optional_parameter', None]
436 448 for i, v in o.get('required_choices', {}).items():
437 449 flags[i] = ['required_choices', v]
438 450 for i, v in o.get('optional_choices', {}).items():
... ... @@ -464,21 +476,21 @@ class Main:
464 476 if kind == 'bare':
465 477 self.json_init.append(
466 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 480 # Optional parameters end up just being the empty string,
469 481 # so the handler has to deal with it. The empty string is
470 482 # also allowed for non-optional.
471 483 self.json_init.append(
472 484 f'addParameter([this](char const* p)'
473 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 486 elif kind == 'required_choices':
479 487 self.json_init.append(
480 488 f'addChoices({v}_choices, true,'
481 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 495 def handle_json_manual(self, path):
484 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 44 QPDF_DLL Config* verbose();
45 45 QPDF_DLL Config* warningExit0();
46 46 QPDF_DLL Config* withImages();
47   -QPDF_DLL Config* collate(char const* parameter);
48   -QPDF_DLL Config* splitPages(char const* parameter);
49 47 QPDF_DLL Config* compressionLevel(char const* parameter);
50 48 QPDF_DLL Config* copyEncryption(char const* parameter);
51 49 QPDF_DLL Config* encryptionFilePassword(char const* parameter);
... ... @@ -65,6 +63,10 @@ QPDF_DLL Config* removeAttachment(char const* parameter);
65 63 QPDF_DLL Config* rotate(char const* parameter);
66 64 QPDF_DLL Config* showAttachment(char const* parameter);
67 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 70 QPDF_DLL Config* compressStreams(char const* parameter);
69 71 QPDF_DLL Config* decodeLevel(char const* parameter);
70 72 QPDF_DLL Config* flattenAnnotations(char const* parameter);
... ... @@ -76,3 +78,4 @@ QPDF_DLL Config* passwordMode(char const* parameter);
76 78 QPDF_DLL Config* removeUnreferencedResources(char const* parameter);
77 79 QPDF_DLL Config* streamData(char const* parameter);
78 80 QPDF_DLL Config* json(char const* parameter);
  81 +QPDF_DLL Config* json();
... ...
job.sums
1 1 # Generated by generate_auto_job
2   -generate_auto_job cb0945a8aa05eb4a523d0931b2cf1a70188e4667d42e012d7621b3aba4f32621
  2 +generate_auto_job 1fdb113412a444aad67b0232f3f6c4f50d9e2a5701691e5146fd1b559039ef2e
3 3 include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e
4 4 include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee
5 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 7 include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671
8 8 include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50
9 9 job.yml effc93a805fb74503be2213ad885238db21991ba3d084fbfeff01183c66cb002
10 10 libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6
11 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 13 libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a357a81f64fe36af2b0cf
14 14 libqpdf/qpdf/auto_job_json_init.hh 3f86ce40931ca8f417d050fcd49104d73c1fa4e977ad19d54b372831a8ea17ed
15 15 libqpdf/qpdf/auto_job_schema.hh 18a3780671d95224cb9a27dcac627c421cae509d59f33a63e6bda0ab53cce923
... ...
libqpdf/QPDFJob_config.cc
... ... @@ -106,6 +106,12 @@ QPDFJob::Config::coalesceContents()
106 106 }
107 107  
108 108 QPDFJob::Config*
  109 +QPDFJob::Config::collate()
  110 +{
  111 + return collate(nullptr);
  112 +}
  113 +
  114 +QPDFJob::Config*
109 115 QPDFJob::Config::collate(char const* parameter)
110 116 {
111 117 auto n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 :
... ... @@ -235,9 +241,15 @@ QPDFJob::Config::isEncrypted()
235 241 }
236 242  
237 243 QPDFJob::Config*
  244 +QPDFJob::Config::json()
  245 +{
  246 + return json(nullptr);
  247 +}
  248 +
  249 +QPDFJob::Config*
238 250 QPDFJob::Config::json(char const* parameter)
239 251 {
240   - if (parameter)
  252 + if (parameter && strlen(parameter))
241 253 {
242 254 if (strcmp(parameter, "latest") == 0)
243 255 {
... ... @@ -517,6 +529,12 @@ QPDFJob::Config::showXref()
517 529 }
518 530  
519 531 QPDFJob::Config*
  532 +QPDFJob::Config::splitPages()
  533 +{
  534 + return splitPages(nullptr);
  535 +}
  536 +
  537 +QPDFJob::Config*
520 538 QPDFJob::Config::splitPages(char const* parameter)
521 539 {
522 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 79 this->ap.addBare("verbose", [this](){c_main->verbose();});
80 80 this->ap.addBare("warning-exit-0", [this](){c_main->warningExit0();});
81 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 82 this->ap.addRequiredParameter("compression-level", [this](char *x){c_main->compressionLevel(x);}, "level");
85 83 this->ap.addRequiredParameter("copy-encryption", [this](char *x){c_main->copyEncryption(x);}, "file");
86 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 98 this->ap.addRequiredParameter("rotate", [this](char *x){c_main->rotate(x);}, "[+|-]angle");
101 99 this->ap.addRequiredParameter("show-attachment", [this](char *x){c_main->showAttachment(x);}, "attachment");
102 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 103 this->ap.addChoices("compress-streams", [this](char *x){c_main->compressStreams(x);}, true, yn_choices);
104 104 this->ap.addChoices("decode-level", [this](char *x){c_main->decodeLevel(x);}, true, decode_level_choices);
105 105 this->ap.addChoices("flatten-annotations", [this](char *x){c_main->flattenAnnotations(x);}, true, flatten_choices);
... ...