Commit daef4e8fb856e84e2a9151cd7715a941a0ae9c6c

Authored by Jay Berkenbilt
1 parent 28cc3692

Add more flexible funtions to qpdfjob C API

ChangeLog
1 2022-06-18 Jay Berkenbilt <ejb@ql.org> 1 2022-06-18 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add additional qpdfjob C API functions take a handle.
  4 +
3 * Add qpdf_exit_code_e to Constants.h so that exit codes from 5 * Add qpdf_exit_code_e to Constants.h so that exit codes from
4 QPDFJob are accessible to the C API. 6 QPDFJob are accessible to the C API.
5 7
include/qpdf/QPDFJob.hh
@@ -108,6 +108,8 @@ class QPDFJob @@ -108,6 +108,8 @@ class QPDFJob
108 // and error streams on the caller's behalf. Defaults to "qpdf". 108 // and error streams on the caller's behalf. Defaults to "qpdf".
109 QPDF_DLL 109 QPDF_DLL
110 void setMessagePrefix(std::string const&); 110 void setMessagePrefix(std::string const&);
  111 + QPDF_DLL
  112 + std::string getMessagePrefix() const;
111 113
112 // To capture or redirect output, configure the logger returned by 114 // To capture or redirect output, configure the logger returned by
113 // getLogger(). By default, all QPDF and QPDFJob objects share the 115 // getLogger(). By default, all QPDF and QPDFJob objects share the
include/qpdf/qpdfjob-c.h
@@ -45,6 +45,11 @@ @@ -45,6 +45,11 @@
45 #ifdef __cplusplus 45 #ifdef __cplusplus
46 extern "C" { 46 extern "C" {
47 #endif 47 #endif
  48 + /* SHORT INTERFACE -- These functions are single calls that take
  49 + * care of the whole life cycle of QPDFJob. They can be used for
  50 + * one-shot ooperations where no additional configuration is
  51 + * needed. See FULL INTERFACE below. */
  52 +
48 /* This function does the equivalent of running the qpdf 53 /* This function does the equivalent of running the qpdf
49 * command-line with the given arguments and returns the exit code 54 * command-line with the given arguments and returns the exit code
50 * that qpdf would use. argv must be a null-terminated array of 55 * that qpdf would use. argv must be a null-terminated array of
@@ -74,6 +79,52 @@ extern &quot;C&quot; { @@ -74,6 +79,52 @@ extern &quot;C&quot; {
74 QPDF_DLL 79 QPDF_DLL
75 int qpdfjob_run_from_json(char const* json); 80 int qpdfjob_run_from_json(char const* json);
76 81
  82 + /* FULL INTERFACE -- new in qpdf11. Similar to the qpdf-c.h API,
  83 + * you must call qpdfjob_init to get a qpdfjob_handle and, when
  84 + * done, call qpdfjob_cleanup to free resources. Remaining methods
  85 + * take qpdfjob_handle as an argument. This interface requires
  86 + * more calls but also offers greater flexibility.
  87 + */
  88 + typedef struct _qpdfjob_handle* qpdfjob_handle;
  89 + QPDF_DLL
  90 + qpdfjob_handle qpdfjob_init();
  91 +
  92 + QPDF_DLL
  93 + void qpdfjob_cleanup(qpdfjob_handle* j);
  94 +
  95 + /* This function wraps QPDFJob::initializeFromArgv. The return
  96 + * value is the same as qpdfjob_run. If this returns an error, it
  97 + * is invalid to call any other functions this job handle.
  98 + */
  99 + QPDF_DLL
  100 + int
  101 + qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[]);
  102 +
  103 +#ifndef QPDF_NO_WCHAR_T
  104 + /* This function is the same as qpdfjob_initialize_from_argv
  105 + * except argv is encoded with wide characters. This would be
  106 + * suitable for calling from a Windows wmain function.
  107 + */
  108 + QPDF_DLL
  109 + int qpdfjob_initialize_from_wide_argv(
  110 + qpdfjob_handle j, wchar_t const* const argv[]);
  111 +#endif /* QPDF_NO_WCHAR_T */
  112 +
  113 + /* This function wraps QPDFJob::initializeFromJson. The return
  114 + * value is the same as qpdfjob_run. If this returns an error, it
  115 + * is invalid to call any other functions this job handle.
  116 + */
  117 + QPDF_DLL
  118 + int qpdfjob_initialize_from_json(qpdfjob_handle j, char const* json);
  119 +
  120 + /* This function wraps QPDFJob::run. It returns the error code
  121 + * that qpdf would return with the equivalent command-line
  122 + * invocation. Exit code values are defined in Constants.h in the
  123 + * qpdf_exit_code_e type.
  124 + */
  125 + QPDF_DLL
  126 + int qpdfjob_run(qpdfjob_handle j);
  127 +
77 #ifdef __cplusplus 128 #ifdef __cplusplus
78 } 129 }
79 #endif 130 #endif
libqpdf/QPDFJob.cc
@@ -438,6 +438,12 @@ QPDFJob::setMessagePrefix(std::string const&amp; message_prefix) @@ -438,6 +438,12 @@ QPDFJob::setMessagePrefix(std::string const&amp; message_prefix)
438 this->m->message_prefix = message_prefix; 438 this->m->message_prefix = message_prefix;
439 } 439 }
440 440
  441 +std::string
  442 +QPDFJob::getMessagePrefix() const
  443 +{
  444 + return this->m->message_prefix;
  445 +}
  446 +
441 std::shared_ptr<QPDFLogger> 447 std::shared_ptr<QPDFLogger>
442 QPDFJob::getLogger() 448 QPDFJob::getLogger()
443 { 449 {
libqpdf/qpdfjob-c.cc
@@ -8,51 +8,115 @@ @@ -8,51 +8,115 @@
8 #include <cstdio> 8 #include <cstdio>
9 #include <cstring> 9 #include <cstring>
10 10
11 -int  
12 -qpdfjob_run_from_argv(char const* const argv[]) 11 +struct _qpdfjob_handle
13 { 12 {
14 - auto whoami_p = QUtil::make_unique_cstr(argv[0]);  
15 - auto whoami = QUtil::getWhoami(whoami_p.get());  
16 - QUtil::setLineBuf(stdout); 13 + _qpdfjob_handle() = default;
  14 + ~_qpdfjob_handle() = default;
17 15
18 QPDFJob j; 16 QPDFJob j;
  17 +};
  18 +
  19 +qpdfjob_handle
  20 +qpdfjob_init()
  21 +{
  22 + return new _qpdfjob_handle;
  23 +}
  24 +
  25 +void
  26 +qpdfjob_cleanup(qpdfjob_handle* j)
  27 +{
  28 + delete *j;
  29 + *j = nullptr;
  30 +}
  31 +
  32 +static int
  33 +wrap_qpdfjob(qpdfjob_handle j, std::function<int(qpdfjob_handle j)> fn)
  34 +{
19 try { 35 try {
20 - j.initializeFromArgv(argv);  
21 - j.run(); 36 + return fn(j);
22 } catch (std::exception& e) { 37 } catch (std::exception& e) {
23 - *QPDFLogger::defaultLogger()->getError()  
24 - << whoami << ": " << e.what() << "\n";  
25 - return QPDFJob::EXIT_ERROR; 38 + *j->j.getLogger()->getError()
  39 + << j->j.getMessagePrefix() << ": " << e.what() << "\n";
26 } 40 }
27 - return j.getExitCode(); 41 + return QPDFJob::EXIT_ERROR;
  42 +}
  43 +
  44 +int
  45 +qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[])
  46 +{
  47 + return wrap_qpdfjob(j, [argv](qpdfjob_handle jh) {
  48 + jh->j.initializeFromArgv(argv);
  49 + return 0;
  50 + });
28 } 51 }
29 52
30 #ifndef QPDF_NO_WCHAR_T 53 #ifndef QPDF_NO_WCHAR_T
31 int 54 int
32 -qpdfjob_run_from_wide_argv(wchar_t const* const argv[]) 55 +qpdfjob_initialize_from_wide_argv(qpdfjob_handle j, wchar_t const* const argv[])
33 { 56 {
34 int argc = 0; 57 int argc = 0;
35 for (auto k = argv; *k; ++k) { 58 for (auto k = argv; *k; ++k) {
36 ++argc; 59 ++argc;
37 } 60 }
38 return QUtil::call_main_from_wmain( 61 return QUtil::call_main_from_wmain(
39 - argc, argv, [](int, char const* const new_argv[]) {  
40 - return qpdfjob_run_from_argv(new_argv); 62 + argc, argv, [j](int, char const* const new_argv[]) {
  63 + return qpdfjob_initialize_from_argv(j, new_argv);
41 }); 64 });
42 } 65 }
43 #endif // QPDF_NO_WCHAR_T 66 #endif // QPDF_NO_WCHAR_T
44 67
45 int 68 int
46 -qpdfjob_run_from_json(char const* json) 69 +qpdfjob_initialize_from_json(qpdfjob_handle j, char const* json)
47 { 70 {
48 - QPDFJob j;  
49 - try {  
50 - j.initializeFromJson(json);  
51 - j.run();  
52 - } catch (std::exception& e) {  
53 - *QPDFLogger::defaultLogger()->getError()  
54 - << "qpdfjob json: " << e.what() << "\n";  
55 - return QPDFJob::EXIT_ERROR; 71 + return wrap_qpdfjob(j, [json](qpdfjob_handle jh) {
  72 + jh->j.setMessagePrefix("qpdfjob json");
  73 + jh->j.initializeFromJson(json);
  74 + return 0;
  75 + });
  76 +}
  77 +
  78 +int
  79 +qpdfjob_run(qpdfjob_handle j)
  80 +{
  81 + QUtil::setLineBuf(stdout);
  82 + return wrap_qpdfjob(j, [](qpdfjob_handle jh) {
  83 + jh->j.run();
  84 + return jh->j.getExitCode();
  85 + });
  86 +}
  87 +
  88 +static int run_with_handle(std::function<int(qpdfjob_handle)> fn)
  89 +{
  90 + auto j = qpdfjob_init();
  91 + int status = fn(j);
  92 + if (status == 0) {
  93 + status = qpdfjob_run(j);
56 } 94 }
57 - return j.getExitCode(); 95 + qpdfjob_cleanup(&j);
  96 + return status;
58 } 97 }
  98 +
  99 +int qpdfjob_run_from_argv(char const* const argv[])
  100 +{
  101 + return run_with_handle([argv](qpdfjob_handle j) {
  102 + return qpdfjob_initialize_from_argv(j, argv);
  103 + });
  104 +}
  105 +
  106 +#ifndef QPDF_NO_WCHAR_T
  107 +int
  108 +qpdfjob_run_from_wide_argv(wchar_t const* const argv[])
  109 +{
  110 + return run_with_handle([argv](qpdfjob_handle j) {
  111 + return qpdfjob_initialize_from_wide_argv(j, argv);
  112 + });
  113 +}
  114 +#endif /* QPDF_NO_WCHAR_T */
  115 +
  116 +int qpdfjob_run_from_json(char const* json)
  117 +{
  118 + return run_with_handle([json](qpdfjob_handle j) {
  119 + return qpdfjob_initialize_from_json(j, json);
  120 + });
  121 +}
  122 +
manual/release-notes.rst
@@ -188,6 +188,13 @@ For a detailed list of changes, please see the file @@ -188,6 +188,13 @@ For a detailed list of changes, please see the file
188 writing large amounts of data without having to keep everything 188 writing large amounts of data without having to keep everything
189 in memory. 189 in memory.
190 190
  191 + - Add new functions to the C API for qpdfjob that use a
  192 + ``qpdfjob_handle``. Like with the regular C API for qpdf, you
  193 + have to call ``qpdfjob_init`` first, pass the handle to the
  194 + functions, and call ``qpdfjob_cleanup`` at the end. This
  195 + interface offers more flexibility than the old interface, which
  196 + remains available.
  197 +
191 - Other changes 198 - Other changes
192 199
193 - In JSON v1 mode, the ``"objects"`` key now reflects the repaired 200 - In JSON v1 mode, the ``"objects"`` key now reflects the repaired
qpdf/qtest/qpdf/qpdfjob-ctest.out
1 argv test passed 1 argv test passed
2 json test passed 2 json test passed
3 WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56 3 WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
4 -qpdf: operation succeeded with warnings; resulting file may have some problems 4 +qpdfjob json: operation succeeded with warnings; resulting file may have some problems
5 json warn test passed 5 json warn test passed
6 qpdfjob json: an output file name is required; use - for standard output 6 qpdfjob json: an output file name is required; use - for standard output
7 json error test passed 7 json error test passed