Commit daef4e8fb856e84e2a9151cd7715a941a0ae9c6c

Authored by Jay Berkenbilt
1 parent 28cc3692

Add more flexible funtions to qpdfjob C API

ChangeLog
1 1 2022-06-18 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Add additional qpdfjob C API functions take a handle.
  4 +
3 5 * Add qpdf_exit_code_e to Constants.h so that exit codes from
4 6 QPDFJob are accessible to the C API.
5 7  
... ...
include/qpdf/QPDFJob.hh
... ... @@ -108,6 +108,8 @@ class QPDFJob
108 108 // and error streams on the caller's behalf. Defaults to "qpdf".
109 109 QPDF_DLL
110 110 void setMessagePrefix(std::string const&);
  111 + QPDF_DLL
  112 + std::string getMessagePrefix() const;
111 113  
112 114 // To capture or redirect output, configure the logger returned by
113 115 // getLogger(). By default, all QPDF and QPDFJob objects share the
... ...
include/qpdf/qpdfjob-c.h
... ... @@ -45,6 +45,11 @@
45 45 #ifdef __cplusplus
46 46 extern "C" {
47 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 53 /* This function does the equivalent of running the qpdf
49 54 * command-line with the given arguments and returns the exit code
50 55 * that qpdf would use. argv must be a null-terminated array of
... ... @@ -74,6 +79,52 @@ extern &quot;C&quot; {
74 79 QPDF_DLL
75 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 128 #ifdef __cplusplus
78 129 }
79 130 #endif
... ...
libqpdf/QPDFJob.cc
... ... @@ -438,6 +438,12 @@ QPDFJob::setMessagePrefix(std::string const&amp; message_prefix)
438 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 447 std::shared_ptr<QPDFLogger>
442 448 QPDFJob::getLogger()
443 449 {
... ...
libqpdf/qpdfjob-c.cc
... ... @@ -8,51 +8,115 @@
8 8 #include <cstdio>
9 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 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 35 try {
20   - j.initializeFromArgv(argv);
21   - j.run();
  36 + return fn(j);
22 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 53 #ifndef QPDF_NO_WCHAR_T
31 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 57 int argc = 0;
35 58 for (auto k = argv; *k; ++k) {
36 59 ++argc;
37 60 }
38 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 66 #endif // QPDF_NO_WCHAR_T
44 67  
45 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 188 writing large amounts of data without having to keep everything
189 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 198 - Other changes
192 199  
193 200 - In JSON v1 mode, the ``"objects"`` key now reflects the repaired
... ...
qpdf/qtest/qpdf/qpdfjob-ctest.out
1 1 argv test passed
2 2 json test passed
3 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 5 json warn test passed
6 6 qpdfjob json: an output file name is required; use - for standard output
7 7 json error test passed
... ...