diff --git a/generate_auto_job b/generate_auto_job index 7f92a630..c63f76c9 100755 --- a/generate_auto_job +++ b/generate_auto_job @@ -4,6 +4,7 @@ import sys import argparse import hashlib import re +import yaml whoami = os.path.basename(sys.argv[0]) BANNER = f'''// @@ -19,6 +20,9 @@ def warn(*args, **kwargs): class Main: SOURCES = [whoami, 'job.yml'] + DESTS = { + 'decl': 'libqpdf/qpdf/auto_job_decl.hh', + } SUMS = 'job.sums' def main(self, args=sys.argv[1:], prog=whoami): @@ -49,11 +53,14 @@ class Main: def get_hashes(self): hashes = {} - for i in sorted(self.SOURCES): + for i in sorted([*self.SOURCES, *self.DESTS.values()]): m = hashlib.sha256() - with open(i, 'rb') as f: - m.update(f.read()) - hashes[i] = m.hexdigest() + try: + with open(i, 'rb') as f: + m.update(f.read()) + hashes[i] = m.hexdigest() + except FileNotFoundError: + pass return hashes def check(self): @@ -82,12 +89,51 @@ class Main: def generate(self): warn(f'{whoami}: regenerating auto job files') - with open('libqpdf/qpdf/auto_job_decl.hh', 'w') as f: - print(BANNER, file=f) + with open('job.yml', 'r') as f: + data = yaml.safe_load(f.read()) + self.validate(data) + self.generate_decl(data) # Update hashes last to ensure that this will be rerun in the # event of a failure. self.update_hashes() + # DON'T ADD CODE TO generate AFTER update_hashes + + def check_keys(self, what, d, exp): + if not isinstance(d, dict): + exit(f'{what} is not a dictionary') + actual = set(d.keys()) + extra = actual - exp + if extra: + exit(f'{what}: unknown keys = {extra}') + + def validate(self, data): + self.check_keys('top', data, set(['choices', 'options'])) + for o in data['options']: + self.check_keys('top', o, set( + ['table', 'bare', 'positional', + 'optional_parameter', 'required_parameter', + 'required_choices', 'from_table'])) + + def to_identifier(self, label, prefix, const): + identifier = re.sub(r'[^a-zA-Z0-9]', '_', label) + if const: + identifier = identifier.upper() + else: + identifier = identifier.lower() + identifier = re.sub('_([a-z])', lambda x: x.group(1).upper(), + identifier) + return prefix + identifier + + def generate_decl(self, data): + with open(self.DESTS['decl'], 'w') as f: + print(BANNER, file=f) + for o in data['options']: + table = o['table'] + if table in ('main', 'help'): + continue + i = self.to_identifier(table, 'O_', True) + print(f'static constexpr char const* {i} = "{table}";', file=f) if __name__ == '__main__': diff --git a/job.sums b/job.sums index 1a7bc00f..7d7e0891 100644 --- a/job.sums +++ b/job.sums @@ -1,3 +1,4 @@ # Generated by generate_auto_job -generate_auto_job 3905985c383d33f9e8629414d1481724ea67d836749f6dff53859ca558325743 +generate_auto_job e0cbb20dade91ebbab5907a53ba83ed3bb4b6cf4bfa75304a4b88e23906fbb6c job.yml 8c66b75eb06be65dfa40058a52cbc0bc18627a3aade5b3d4e034543605c93298 +libqpdf/qpdf/auto_job_decl.hh b098ee02ec853f47850b6421cc72b08c608f303f74f01d0b3ce3df52cecd5ffa diff --git a/libqpdf/QPDFJob_argv.cc b/libqpdf/QPDFJob_argv.cc index 2e35bd74..55f235bf 100644 --- a/libqpdf/QPDFJob_argv.cc +++ b/libqpdf/QPDFJob_argv.cc @@ -23,14 +23,7 @@ namespace void parseOptions(); private: - static constexpr char const* O_PAGES = "pages"; - static constexpr char const* O_ENCRYPT = "encryption"; - static constexpr char const* O_ENCRYPT_40 = "40-bit encryption"; - static constexpr char const* O_ENCRYPT_128 = "128-bit encryption"; - static constexpr char const* O_ENCRYPT_256 = "256-bit encryption"; - static constexpr char const* O_UNDER_OVERLAY = "underlay/overlay"; - static constexpr char const* O_ATTACHMENT = "attachment"; - static constexpr char const* O_COPY_ATTACHMENT = "copy attachment"; +# include void argHelp(); void argVersion(); @@ -344,16 +337,16 @@ ArgParser::initOptionTable() this->ap.selectMainOptionTable(); this->ap.addBare("encrypt", b(&ArgParser::argEncrypt)); - this->ap.registerOptionTable(O_ENCRYPT, b(&ArgParser::argEndEncrypt)); + this->ap.registerOptionTable(O_ENCRYPTION, b(&ArgParser::argEndEncrypt)); this->ap.addPositional(p(&ArgParser::argEncryptPositional)); - this->ap.registerOptionTable(O_ENCRYPT_40, b(&ArgParser::argEndEncrypt)); + this->ap.registerOptionTable(O_40_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); this->ap.addRequiredChoices("extract",p(&ArgParser::arg40Extract), yn); this->ap.addRequiredChoices("annotate",p(&ArgParser::arg40Annotate), yn); this->ap.addRequiredChoices("print",p(&ArgParser::arg40Print), yn); this->ap.addRequiredChoices("modify",p(&ArgParser::arg40Modify), yn); - this->ap.registerOptionTable(O_ENCRYPT_128, b(&ArgParser::argEndEncrypt)); - this->ap.registerOptionTable(O_ENCRYPT_256, b(&ArgParser::argEndEncrypt)); - for (char const* k: {O_ENCRYPT_128, O_ENCRYPT_256}) + this->ap.registerOptionTable(O_128_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); + this->ap.registerOptionTable(O_256_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); + for (char const* k: {O_128_BIT_ENCRYPTION, O_256_BIT_ENCRYPTION}) { this->ap.selectOptionTable(k); this->ap.addRequiredChoices("accessibility", @@ -373,15 +366,15 @@ ArgParser::initOptionTable() this->ap.addBare("cleartext-metadata", b(&ArgParser::arg128ClearTextMetadata)); } - this->ap.selectOptionTable(O_ENCRYPT_128); + this->ap.selectOptionTable(O_128_BIT_ENCRYPTION); this->ap.addRequiredChoices("use-aes",p(&ArgParser::arg128UseAes), yn); this->ap.addBare("force-V4", b(&ArgParser::arg128ForceV4)); - this->ap.selectOptionTable(O_ENCRYPT_256); + this->ap.selectOptionTable(O_256_BIT_ENCRYPTION); this->ap.addBare("force-R5", b(&ArgParser::arg256ForceR5)); this->ap.addBare("allow-insecure", b(&ArgParser::argAllowInsecure)); - this->ap.registerOptionTable(O_UNDER_OVERLAY, b(&ArgParser::argEndUnderOverlay)); + this->ap.registerOptionTable(O_UNDERLAY_OVERLAY, b(&ArgParser::argEndUnderOverlay)); this->ap.addPositional(p(&ArgParser::argUOpositional)); this->ap.addRequiredParameter("to", p(&ArgParser::argUOto), "page-range"); @@ -1089,7 +1082,7 @@ ArgParser::argEncrypt() { this->ap.insertCompletion("user-password"); } - this->ap.selectOptionTable(O_ENCRYPT); + this->ap.selectOptionTable(O_ENCRYPTION); } void @@ -1120,18 +1113,18 @@ ArgParser::argEncryptPositional(char* arg) if (len_str == "40") { o.keylen = 40; - this->ap.selectOptionTable(O_ENCRYPT_40); + this->ap.selectOptionTable(O_40_BIT_ENCRYPTION); } else if (len_str == "128") { o.keylen = 128; - this->ap.selectOptionTable(O_ENCRYPT_128); + this->ap.selectOptionTable(O_128_BIT_ENCRYPTION); } else if (len_str == "256") { o.keylen = 256; o.use_aes = true; - this->ap.selectOptionTable(O_ENCRYPT_256); + this->ap.selectOptionTable(O_256_BIT_ENCRYPTION); } else { @@ -2202,7 +2195,7 @@ void ArgParser::parseUnderOverlayOptions(QPDFJob::UnderOverlay* uo) { o.under_overlay = uo; - this->ap.selectOptionTable(O_UNDER_OVERLAY); + this->ap.selectOptionTable(O_UNDERLAY_OVERLAY); } void diff --git a/libqpdf/qpdf/auto_job_decl.hh b/libqpdf/qpdf/auto_job_decl.hh index d6cbecfe..806e2ab5 100644 --- a/libqpdf/qpdf/auto_job_decl.hh +++ b/libqpdf/qpdf/auto_job_decl.hh @@ -3,3 +3,11 @@ // Edits will be automatically overwritten if the build is // run in maintainer mode. // +static constexpr char const* O_PAGES = "pages"; +static constexpr char const* O_ENCRYPTION = "encryption"; +static constexpr char const* O_40_BIT_ENCRYPTION = "40-bit encryption"; +static constexpr char const* O_128_BIT_ENCRYPTION = "128-bit encryption"; +static constexpr char const* O_256_BIT_ENCRYPTION = "256-bit encryption"; +static constexpr char const* O_UNDERLAY_OVERLAY = "underlay/overlay"; +static constexpr char const* O_ATTACHMENT = "attachment"; +static constexpr char const* O_COPY_ATTACHMENT = "copy attachment";