Commit 8130d50e3b5aa0235a133c3c5a3018ac01afb5e1
1 parent
daef4e8f
Add C API to QPDFLogger
Showing
23 changed files
with
592 additions
and
15 deletions
ChangeLog
| 1 | 2022-06-18 Jay Berkenbilt <ejb@ql.org> | 1 | 2022-06-18 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * Add examples that show how to capture QPDFJob's output by | ||
| 4 | + configuring the default logger (qpdfjob-save-attachment.cc, | ||
| 5 | + qpdfjob-c-save-attachment.c). Fixes #691. | ||
| 6 | + | ||
| 7 | + * Add C API for QPDFLogger -- see qpdflogger-c.h | ||
| 8 | + | ||
| 3 | * Add additional qpdfjob C API functions take a handle. | 9 | * Add additional qpdfjob C API functions take a handle. |
| 4 | 10 | ||
| 5 | * Add qpdf_exit_code_e to Constants.h so that exit codes from | 11 | * Add qpdf_exit_code_e to Constants.h so that exit codes from |
include/qpdf/QPDFLogger.hh
| @@ -130,9 +130,9 @@ class QPDFLogger | @@ -130,9 +130,9 @@ class QPDFLogger | ||
| 130 | void setError(std::shared_ptr<Pipeline>); | 130 | void setError(std::shared_ptr<Pipeline>); |
| 131 | // See notes above about the save pipeline | 131 | // See notes above about the save pipeline |
| 132 | QPDF_DLL | 132 | QPDF_DLL |
| 133 | - void setSave(std::shared_ptr<Pipeline>); | 133 | + void setSave(std::shared_ptr<Pipeline>, bool only_if_not_set); |
| 134 | QPDF_DLL | 134 | QPDF_DLL |
| 135 | - void saveToStandardOutput(); | 135 | + void saveToStandardOutput(bool only_if_not_set); |
| 136 | 136 | ||
| 137 | // Shortcut for logic to reset output to new output/error streams. | 137 | // Shortcut for logic to reset output to new output/error streams. |
| 138 | // out_stream is used for info, err_stream is used for error, and | 138 | // out_stream is used for info, err_stream is used for error, and |
include/qpdf/qpdflogger-c.h
0 → 100644
| 1 | +/* Copyright (c) 2005-2022 Jay Berkenbilt | ||
| 2 | + * | ||
| 3 | + * This file is part of qpdf. | ||
| 4 | + * | ||
| 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | + * you may not use this file except in compliance with the License. | ||
| 7 | + * You may obtain a copy of the License at | ||
| 8 | + * | ||
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + * | ||
| 11 | + * Unless required by applicable law or agreed to in writing, software | ||
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + * See the License for the specific language governing permissions and | ||
| 15 | + * limitations under the License. | ||
| 16 | + * | ||
| 17 | + * Versions of qpdf prior to version 7 were released under the terms | ||
| 18 | + * of version 2.0 of the Artistic License. At your option, you may | ||
| 19 | + * continue to consider qpdf to be licensed under those terms. Please | ||
| 20 | + * see the manual for additional information. | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | +#ifndef QPDFLOGGER_H | ||
| 24 | +#define QPDFLOGGER_H | ||
| 25 | + | ||
| 26 | +/* | ||
| 27 | + * This file provides a C API for QPDFLogger. See QPDFLogger.hh for | ||
| 28 | + * information about the logger. | ||
| 29 | + */ | ||
| 30 | + | ||
| 31 | +#include <qpdf/DLL.h> | ||
| 32 | +#include <stddef.h> | ||
| 33 | + | ||
| 34 | +#ifdef __cplusplus | ||
| 35 | +extern "C" { | ||
| 36 | +#endif | ||
| 37 | + | ||
| 38 | + /* To operate on a logger, you need a handle to it. call | ||
| 39 | + * qpdflogger_default_logger to get a handle for the default | ||
| 40 | + * logger. The qpdf and qpdfjob functions may offer ways to get | ||
| 41 | + * other logger handles. When you're done with the logger handler, | ||
| 42 | + * call qpdflogger_cleanup. This does not destroy the underlying | ||
| 43 | + * log object. It just cleans up the handle to it. | ||
| 44 | + */ | ||
| 45 | + | ||
| 46 | + typedef struct _qpdflogger_handle* qpdflogger_handle; | ||
| 47 | + QPDF_DLL | ||
| 48 | + qpdflogger_handle qpdflogger_default_logger(); | ||
| 49 | + | ||
| 50 | + QPDF_DLL | ||
| 51 | + void qpdflogger_cleanup(qpdflogger_handle* l); | ||
| 52 | + | ||
| 53 | + enum qpdf_log_dest_e { | ||
| 54 | + qpdf_log_dest_default = 0, | ||
| 55 | + qpdf_log_dest_stdout = 1, | ||
| 56 | + qpdf_log_dest_stderr = 2, | ||
| 57 | + qpdf_log_dest_discard = 3, | ||
| 58 | + qpdf_log_dest_custom = 4, | ||
| 59 | + }; | ||
| 60 | + | ||
| 61 | + typedef void (*qpdf_log_fn_t)(char const* data, size_t len, void* udata); | ||
| 62 | + | ||
| 63 | + QPDF_DLL | ||
| 64 | + void qpdflogger_set_info( | ||
| 65 | + qpdflogger_handle l, | ||
| 66 | + enum qpdf_log_dest_e dest, | ||
| 67 | + qpdf_log_fn_t fn, | ||
| 68 | + void* udata); | ||
| 69 | + QPDF_DLL | ||
| 70 | + void qpdflogger_set_warn( | ||
| 71 | + qpdflogger_handle l, | ||
| 72 | + enum qpdf_log_dest_e dest, | ||
| 73 | + qpdf_log_fn_t fn, | ||
| 74 | + void* udata); | ||
| 75 | + QPDF_DLL | ||
| 76 | + void qpdflogger_set_error( | ||
| 77 | + qpdflogger_handle l, | ||
| 78 | + enum qpdf_log_dest_e dest, | ||
| 79 | + qpdf_log_fn_t fn, | ||
| 80 | + void* udata); | ||
| 81 | + | ||
| 82 | + /* A non-zero value for only_if_not_set means that the save | ||
| 83 | + * pipeline will only be changed if it is not already set. | ||
| 84 | + */ | ||
| 85 | + QPDF_DLL | ||
| 86 | + void qpdflogger_set_save( | ||
| 87 | + qpdflogger_handle l, | ||
| 88 | + enum qpdf_log_dest_e dest, | ||
| 89 | + qpdf_log_fn_t fn, | ||
| 90 | + void* udata, | ||
| 91 | + int only_if_not_set); | ||
| 92 | + QPDF_DLL | ||
| 93 | + void qpdflogger_save_to_standard_output( | ||
| 94 | + qpdflogger_handle l, int only_if_not_set); | ||
| 95 | + | ||
| 96 | +#ifdef __cplusplus | ||
| 97 | +} | ||
| 98 | +#endif | ||
| 99 | + | ||
| 100 | +#endif // QPDFLOGGER_H |
libqpdf/CMakeLists.txt
| @@ -110,7 +110,8 @@ set(libqpdf_SOURCES | @@ -110,7 +110,8 @@ set(libqpdf_SOURCES | ||
| 110 | SF_FlateLzwDecode.cc | 110 | SF_FlateLzwDecode.cc |
| 111 | SparseOHArray.cc | 111 | SparseOHArray.cc |
| 112 | qpdf-c.cc | 112 | qpdf-c.cc |
| 113 | - qpdfjob-c.cc) | 113 | + qpdfjob-c.cc |
| 114 | + qpdflogger-c.cc) | ||
| 114 | 115 | ||
| 115 | include(FindPkgConfig) | 116 | include(FindPkgConfig) |
| 116 | include(CheckTypeSize) | 117 | include(CheckTypeSize) |
libqpdf/QPDFJob.cc
| @@ -710,7 +710,7 @@ QPDFJob::checkConfiguration() | @@ -710,7 +710,7 @@ QPDFJob::checkConfiguration() | ||
| 710 | save_to_stdout = true; | 710 | save_to_stdout = true; |
| 711 | } | 711 | } |
| 712 | if (save_to_stdout) { | 712 | if (save_to_stdout) { |
| 713 | - this->m->log->saveToStandardOutput(); | 713 | + this->m->log->saveToStandardOutput(true); |
| 714 | } | 714 | } |
| 715 | if ((!m->split_pages) && | 715 | if ((!m->split_pages) && |
| 716 | QUtil::same_file(m->infilename.get(), m->outfilename.get())) { | 716 | QUtil::same_file(m->infilename.get(), m->outfilename.get())) { |
| @@ -925,7 +925,7 @@ QPDFJob::doShowObj(QPDF& pdf) | @@ -925,7 +925,7 @@ QPDFJob::doShowObj(QPDF& pdf) | ||
| 925 | } else { | 925 | } else { |
| 926 | // If anything has been written to standard output, | 926 | // If anything has been written to standard output, |
| 927 | // this will fail. | 927 | // this will fail. |
| 928 | - this->m->log->saveToStandardOutput(); | 928 | + this->m->log->saveToStandardOutput(true); |
| 929 | obj.pipeStreamData( | 929 | obj.pipeStreamData( |
| 930 | this->m->log->getSave().get(), | 930 | this->m->log->getSave().get(), |
| 931 | (filter && m->normalize) ? qpdf_ef_normalize : 0, | 931 | (filter && m->normalize) ? qpdf_ef_normalize : 0, |
| @@ -1031,7 +1031,7 @@ QPDFJob::doShowAttachment(QPDF& pdf) | @@ -1031,7 +1031,7 @@ QPDFJob::doShowAttachment(QPDF& pdf) | ||
| 1031 | auto efs = fs->getEmbeddedFileStream(); | 1031 | auto efs = fs->getEmbeddedFileStream(); |
| 1032 | // saveToStandardOutput has already been called, but it's harmless | 1032 | // saveToStandardOutput has already been called, but it's harmless |
| 1033 | // to call it again, so do as defensive coding. | 1033 | // to call it again, so do as defensive coding. |
| 1034 | - this->m->log->saveToStandardOutput(); | 1034 | + this->m->log->saveToStandardOutput(true); |
| 1035 | efs.pipeStreamData(this->m->log->getSave().get(), 0, qpdf_dl_all); | 1035 | efs.pipeStreamData(this->m->log->getSave().get(), 0, qpdf_dl_all); |
| 1036 | } | 1036 | } |
| 1037 | 1037 | ||
| @@ -3289,7 +3289,7 @@ QPDFJob::writeOutfile(QPDF& pdf) | @@ -3289,7 +3289,7 @@ QPDFJob::writeOutfile(QPDF& pdf) | ||
| 3289 | } else { | 3289 | } else { |
| 3290 | // saveToStandardOutput has already been called, but | 3290 | // saveToStandardOutput has already been called, but |
| 3291 | // calling it again is defensive and harmless. | 3291 | // calling it again is defensive and harmless. |
| 3292 | - this->m->log->saveToStandardOutput(); | 3292 | + this->m->log->saveToStandardOutput(true); |
| 3293 | w.setOutputPipeline(this->m->log->getSave().get()); | 3293 | w.setOutputPipeline(this->m->log->getSave().get()); |
| 3294 | } | 3294 | } |
| 3295 | setWriterOptions(pdf, w); | 3295 | setWriterOptions(pdf, w); |
libqpdf/QPDFLogger.cc
| @@ -181,8 +181,11 @@ QPDFLogger::setError(std::shared_ptr<Pipeline> p) | @@ -181,8 +181,11 @@ QPDFLogger::setError(std::shared_ptr<Pipeline> p) | ||
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | void | 183 | void |
| 184 | -QPDFLogger::setSave(std::shared_ptr<Pipeline> p) | 184 | +QPDFLogger::setSave(std::shared_ptr<Pipeline> p, bool only_if_not_set) |
| 185 | { | 185 | { |
| 186 | + if (only_if_not_set && (this->m->p_save != nullptr)) { | ||
| 187 | + return; | ||
| 188 | + } | ||
| 186 | if (this->m->p_save == p) { | 189 | if (this->m->p_save == p) { |
| 187 | return; | 190 | return; |
| 188 | } | 191 | } |
| @@ -202,9 +205,9 @@ QPDFLogger::setSave(std::shared_ptr<Pipeline> p) | @@ -202,9 +205,9 @@ QPDFLogger::setSave(std::shared_ptr<Pipeline> p) | ||
| 202 | } | 205 | } |
| 203 | 206 | ||
| 204 | void | 207 | void |
| 205 | -QPDFLogger::saveToStandardOutput() | 208 | +QPDFLogger::saveToStandardOutput(bool only_if_not_set) |
| 206 | { | 209 | { |
| 207 | - setSave(standardOutput()); | 210 | + setSave(standardOutput(), only_if_not_set); |
| 208 | } | 211 | } |
| 209 | 212 | ||
| 210 | void | 213 | void |
libqpdf/qpdflogger-c.cc
0 → 100644
| 1 | +#include <qpdf/qpdflogger-c.h> | ||
| 2 | + | ||
| 3 | +#include <qpdf/Pipeline.hh> | ||
| 4 | +#include <qpdf/QIntC.hh> | ||
| 5 | +#include <qpdf/QPDFLogger.hh> | ||
| 6 | +#include <functional> | ||
| 7 | +#include <memory> | ||
| 8 | + | ||
| 9 | +struct _qpdflogger_handle | ||
| 10 | +{ | ||
| 11 | + _qpdflogger_handle(std::shared_ptr<QPDFLogger> l); | ||
| 12 | + ~_qpdflogger_handle() = default; | ||
| 13 | + | ||
| 14 | + std::shared_ptr<QPDFLogger> l; | ||
| 15 | +}; | ||
| 16 | + | ||
| 17 | +namespace | ||
| 18 | +{ | ||
| 19 | + class FunctionPipeline: public Pipeline | ||
| 20 | + { | ||
| 21 | + public: | ||
| 22 | + FunctionPipeline(char const* identifier, qpdf_log_fn_t fn, void* udata); | ||
| 23 | + virtual ~FunctionPipeline() = default; | ||
| 24 | + | ||
| 25 | + virtual void write(unsigned char const* buf, size_t len) override; | ||
| 26 | + virtual void finish() override; | ||
| 27 | + | ||
| 28 | + private: | ||
| 29 | + qpdf_log_fn_t fn; | ||
| 30 | + void* udata; | ||
| 31 | + }; | ||
| 32 | +}; // namespace | ||
| 33 | + | ||
| 34 | +FunctionPipeline::FunctionPipeline( | ||
| 35 | + char const* identifier, qpdf_log_fn_t fn, void* udata) : | ||
| 36 | + Pipeline(identifier, nullptr), | ||
| 37 | + fn(fn), | ||
| 38 | + udata(udata) | ||
| 39 | +{ | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +void | ||
| 43 | +FunctionPipeline::write(unsigned char const* buf, size_t len) | ||
| 44 | +{ | ||
| 45 | + fn(reinterpret_cast<char const*>(buf), QIntC::to_ulong(len), udata); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +void | ||
| 49 | +FunctionPipeline::finish() | ||
| 50 | +{ | ||
| 51 | + // Nothing needed | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +_qpdflogger_handle::_qpdflogger_handle(std::shared_ptr<QPDFLogger> l) : | ||
| 55 | + l(l) | ||
| 56 | +{ | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +qpdflogger_handle | ||
| 60 | +qpdflogger_default_logger() | ||
| 61 | +{ | ||
| 62 | + return new _qpdflogger_handle(QPDFLogger::defaultLogger()); | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +void | ||
| 66 | +qpdflogger_cleanup(qpdflogger_handle* l) | ||
| 67 | +{ | ||
| 68 | + delete *l; | ||
| 69 | + *l = nullptr; | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +static void | ||
| 73 | +set_log_dest( | ||
| 74 | + QPDFLogger* l, | ||
| 75 | + std::function<void(std::shared_ptr<Pipeline>)> method, | ||
| 76 | + qpdf_log_dest_e dest, | ||
| 77 | + char const* identifier, | ||
| 78 | + qpdf_log_fn_t fn, | ||
| 79 | + void* udata) | ||
| 80 | +{ | ||
| 81 | + switch (dest) { | ||
| 82 | + case qpdf_log_dest_default: | ||
| 83 | + method(nullptr); | ||
| 84 | + break; | ||
| 85 | + case qpdf_log_dest_stdout: | ||
| 86 | + method(l->standardOutput()); | ||
| 87 | + break; | ||
| 88 | + case qpdf_log_dest_stderr: | ||
| 89 | + method(l->standardError()); | ||
| 90 | + break; | ||
| 91 | + case qpdf_log_dest_discard: | ||
| 92 | + method(l->discard()); | ||
| 93 | + break; | ||
| 94 | + case qpdf_log_dest_custom: | ||
| 95 | + method(std::make_shared<FunctionPipeline>(identifier, fn, udata)); | ||
| 96 | + break; | ||
| 97 | + } | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +static void | ||
| 101 | +set_log_dest( | ||
| 102 | + QPDFLogger* l, | ||
| 103 | + void (QPDFLogger::*method)(std::shared_ptr<Pipeline>), | ||
| 104 | + qpdf_log_dest_e dest, | ||
| 105 | + char const* identifier, | ||
| 106 | + qpdf_log_fn_t fn, | ||
| 107 | + void* udata) | ||
| 108 | +{ | ||
| 109 | + set_log_dest( | ||
| 110 | + l, | ||
| 111 | + std::bind(std::mem_fn(method), l, std::placeholders::_1), | ||
| 112 | + dest, | ||
| 113 | + identifier, | ||
| 114 | + fn, | ||
| 115 | + udata); | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +void | ||
| 119 | +qpdflogger_set_info( | ||
| 120 | + qpdflogger_handle l, qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata) | ||
| 121 | +{ | ||
| 122 | + set_log_dest( | ||
| 123 | + l->l.get(), &QPDFLogger::setInfo, dest, "info logger", fn, udata); | ||
| 124 | +} | ||
| 125 | + | ||
| 126 | +void | ||
| 127 | +qpdflogger_set_warn( | ||
| 128 | + qpdflogger_handle l, qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata) | ||
| 129 | +{ | ||
| 130 | + set_log_dest( | ||
| 131 | + l->l.get(), &QPDFLogger::setWarn, dest, "warn logger", fn, udata); | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +void | ||
| 135 | +qpdflogger_set_error( | ||
| 136 | + qpdflogger_handle l, qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata) | ||
| 137 | +{ | ||
| 138 | + set_log_dest( | ||
| 139 | + l->l.get(), &QPDFLogger::setError, dest, "error logger", fn, udata); | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +void | ||
| 143 | +qpdflogger_set_save( | ||
| 144 | + qpdflogger_handle l, | ||
| 145 | + qpdf_log_dest_e dest, | ||
| 146 | + qpdf_log_fn_t fn, | ||
| 147 | + void* udata, | ||
| 148 | + int only_if_not_set) | ||
| 149 | +{ | ||
| 150 | + auto method = std::bind( | ||
| 151 | + std::mem_fn(&QPDFLogger::setSave), | ||
| 152 | + l->l.get(), | ||
| 153 | + std::placeholders::_1, | ||
| 154 | + only_if_not_set); | ||
| 155 | + set_log_dest(l->l.get(), method, dest, "save logger", fn, udata); | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +void | ||
| 159 | +qpdflogger_save_to_standard_output(qpdflogger_handle l, int only_if_not_set) | ||
| 160 | +{ | ||
| 161 | + qpdflogger_set_save( | ||
| 162 | + l, qpdf_log_dest_stdout, nullptr, nullptr, only_if_not_set); | ||
| 163 | +} |
libtests/CMakeLists.txt
| @@ -33,10 +33,18 @@ set(TEST_PROGRAMS | @@ -33,10 +33,18 @@ set(TEST_PROGRAMS | ||
| 33 | runlength | 33 | runlength |
| 34 | sha2 | 34 | sha2 |
| 35 | sparse_array) | 35 | sparse_array) |
| 36 | +set(TEST_C_PROGRAMS | ||
| 37 | + logger_c) | ||
| 38 | + | ||
| 36 | foreach(PROG ${TEST_PROGRAMS}) | 39 | foreach(PROG ${TEST_PROGRAMS}) |
| 37 | add_executable(${PROG} ${PROG}.cc) | 40 | add_executable(${PROG} ${PROG}.cc) |
| 38 | target_link_libraries(${PROG} libqpdf_object) | 41 | target_link_libraries(${PROG} libqpdf_object) |
| 39 | endforeach() | 42 | endforeach() |
| 43 | +foreach(PROG ${TEST_C_PROGRAMS}) | ||
| 44 | + add_executable(${PROG} ${PROG}.c) | ||
| 45 | + target_link_libraries(${PROG} libqpdf_object) | ||
| 46 | + set_property(TARGET ${PROG} PROPERTY LINKER_LANGUAGE CXX) | ||
| 47 | +endforeach() | ||
| 40 | 48 | ||
| 41 | # Since libtests link with the object library and don't use the DLL, | 49 | # Since libtests link with the object library and don't use the DLL, |
| 42 | # we don't need to (and shouldn't) add the libqpdf target directory to | 50 | # we don't need to (and shouldn't) add the libqpdf target directory to |
libtests/logger.cc
| @@ -22,7 +22,7 @@ test1() | @@ -22,7 +22,7 @@ test1() | ||
| 22 | *(logger->getInfo()) << "getSave exception: " << e.what() << "\n"; | 22 | *(logger->getInfo()) << "getSave exception: " << e.what() << "\n"; |
| 23 | } | 23 | } |
| 24 | try { | 24 | try { |
| 25 | - logger->saveToStandardOutput(); | 25 | + logger->saveToStandardOutput(true); |
| 26 | assert(false); | 26 | assert(false); |
| 27 | } catch (std::logic_error& e) { | 27 | } catch (std::logic_error& e) { |
| 28 | *(logger->getInfo()) | 28 | *(logger->getInfo()) |
| @@ -40,12 +40,12 @@ test2() | @@ -40,12 +40,12 @@ test2() | ||
| 40 | // First call saveToStandardOutput. Then use info, which then to | 40 | // First call saveToStandardOutput. Then use info, which then to |
| 41 | // go stderr. | 41 | // go stderr. |
| 42 | QPDFLogger l; | 42 | QPDFLogger l; |
| 43 | - l.saveToStandardOutput(); | 43 | + l.saveToStandardOutput(true); |
| 44 | l.info(std::string("info to stderr\n")); | 44 | l.info(std::string("info to stderr\n")); |
| 45 | *(l.getSave()) << "save to stdout\n"; | 45 | *(l.getSave()) << "save to stdout\n"; |
| 46 | l.setInfo(nullptr); | 46 | l.setInfo(nullptr); |
| 47 | l.info("info still to stderr\n"); | 47 | l.info("info still to stderr\n"); |
| 48 | - l.setSave(nullptr); | 48 | + l.setSave(nullptr, false); |
| 49 | l.setInfo(nullptr); | 49 | l.setInfo(nullptr); |
| 50 | l.info("info back to stdout\n"); | 50 | l.info("info back to stdout\n"); |
| 51 | } | 51 | } |
libtests/logger_c.c
0 → 100644
| 1 | +#include <qpdf/assert_test.h> | ||
| 2 | + | ||
| 3 | +#include <qpdf/qpdflogger-c.h> | ||
| 4 | + | ||
| 5 | +#include <qpdf/Constants.h> | ||
| 6 | +#include <qpdf/qpdfjob-c.h> | ||
| 7 | + | ||
| 8 | +#include <stdio.h> | ||
| 9 | +#include <stdlib.h> | ||
| 10 | + | ||
| 11 | +static void | ||
| 12 | +fn(char const* data, size_t len, void* udata) | ||
| 13 | +{ | ||
| 14 | + FILE* f = (FILE*)udata; | ||
| 15 | + fwrite(data, 1, len, f); | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +static void | ||
| 19 | +do_run(char const* json, int exp_status) | ||
| 20 | +{ | ||
| 21 | + int status = qpdfjob_run_from_json(json); | ||
| 22 | + assert(status == exp_status); | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +static FILE* | ||
| 26 | +do_fopen(char const* filename) | ||
| 27 | +{ | ||
| 28 | + FILE* f = NULL; | ||
| 29 | +#ifdef _MSC_VER | ||
| 30 | + if (fopen_s(&f, filename, "wb") != 0) { | ||
| 31 | + f = NULL; | ||
| 32 | + } | ||
| 33 | +#else | ||
| 34 | + f = fopen(filename, "wb"); | ||
| 35 | +#endif | ||
| 36 | + if (f == NULL) { | ||
| 37 | + fprintf(stderr, "unable to open %s\n", filename); | ||
| 38 | + exit(2); | ||
| 39 | + } | ||
| 40 | + return f; | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +int | ||
| 44 | +main() | ||
| 45 | +{ | ||
| 46 | + FILE* info = do_fopen("info"); | ||
| 47 | + FILE* warn = do_fopen("warn"); | ||
| 48 | + FILE* error = do_fopen("error"); | ||
| 49 | + FILE* save = do_fopen("save"); | ||
| 50 | + FILE* save2 = do_fopen("save2"); | ||
| 51 | + qpdflogger_handle l = qpdflogger_default_logger(); | ||
| 52 | + | ||
| 53 | + qpdflogger_set_info(l, qpdf_log_dest_custom, fn, (void*)info); | ||
| 54 | + qpdflogger_set_warn(l, qpdf_log_dest_custom, fn, (void*)warn); | ||
| 55 | + qpdflogger_set_error(l, qpdf_log_dest_custom, fn, (void*)error); | ||
| 56 | + qpdflogger_set_save(l, qpdf_log_dest_custom, fn, (void*)save, 0); | ||
| 57 | + | ||
| 58 | + do_run( | ||
| 59 | + "{\"inputFile\": \"normal.pdf\", \"showNpages\": \"\"}", | ||
| 60 | + qpdf_exit_success); | ||
| 61 | + do_run( | ||
| 62 | + "{\"inputFile\": \"warning.pdf\", \"showNpages\": \"\"}", | ||
| 63 | + qpdf_exit_warning); | ||
| 64 | + do_run( | ||
| 65 | + "{\"inputFile\": \"missing.pdf\", \"showNpages\": \"\"}", | ||
| 66 | + qpdf_exit_error); | ||
| 67 | + do_run( | ||
| 68 | + "{\"inputFile\": \"normal.pdf\"," | ||
| 69 | + " \"staticId\": \"\"," | ||
| 70 | + " \"outputFile\": \"-\"}", | ||
| 71 | + qpdf_exit_success); | ||
| 72 | + | ||
| 73 | + fclose(info); | ||
| 74 | + fclose(warn); | ||
| 75 | + fclose(error); | ||
| 76 | + fclose(save); | ||
| 77 | + | ||
| 78 | + qpdflogger_set_info(l, qpdf_log_dest_stderr, NULL, NULL); | ||
| 79 | + qpdflogger_set_warn(l, qpdf_log_dest_stdout, NULL, NULL); | ||
| 80 | + qpdflogger_set_error(l, qpdf_log_dest_default, NULL, NULL); | ||
| 81 | + qpdflogger_set_save(l, qpdf_log_dest_custom, fn, (void*)save2, 0); | ||
| 82 | + | ||
| 83 | + do_run( | ||
| 84 | + "{\"inputFile\": \"2pages.pdf\", \"showNpages\": \"\"}", | ||
| 85 | + qpdf_exit_success); | ||
| 86 | + do_run( | ||
| 87 | + "{\"inputFile\": \"warning.pdf\", \"showNpages\": \"\"}", | ||
| 88 | + qpdf_exit_warning); | ||
| 89 | + do_run( | ||
| 90 | + | ||
| 91 | + "{\"inputFile\": \"missing.pdf\", \"showNpages\": \"\"}", | ||
| 92 | + qpdf_exit_error); | ||
| 93 | + do_run( | ||
| 94 | + "{\"inputFile\": \"attach.pdf\"," | ||
| 95 | + " \"showAttachment\": \"a\"}", | ||
| 96 | + qpdf_exit_success); | ||
| 97 | + | ||
| 98 | + /* This won't change save since it's already set */ | ||
| 99 | + qpdflogger_save_to_standard_output(l, 1); | ||
| 100 | + do_run( | ||
| 101 | + "{\"inputFile\": \"attach.pdf\"," | ||
| 102 | + " \"showAttachment\": \"a\"}", | ||
| 103 | + qpdf_exit_success); | ||
| 104 | + | ||
| 105 | + qpdflogger_cleanup(&l); | ||
| 106 | + | ||
| 107 | + return 0; | ||
| 108 | +} |
libtests/qtest/logger.test
| @@ -24,10 +24,22 @@ $td->runtest("check stderr", | @@ -24,10 +24,22 @@ $td->runtest("check stderr", | ||
| 24 | {$td->FILE => "exp-stderr"}, | 24 | {$td->FILE => "exp-stderr"}, |
| 25 | $td->NORMALIZE_NEWLINES); | 25 | $td->NORMALIZE_NEWLINES); |
| 26 | 26 | ||
| 27 | +$td->runtest("logger C API", | ||
| 28 | + {$td->COMMAND => "logger_c >stdout 2>stderr"}, | ||
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | ||
| 30 | + $td->NORMALIZE_NEWLINES); | ||
| 31 | +foreach my $f (qw(stdout stderr info warn error save save2)) | ||
| 32 | +{ | ||
| 33 | + $td->runtest("check $f (C)", | ||
| 34 | + {$td->FILE => "$f"}, | ||
| 35 | + {$td->FILE => "c-exp-$f"}, | ||
| 36 | + $td->NORMALIZE_NEWLINES); | ||
| 37 | +} | ||
| 38 | + | ||
| 27 | cleanup(); | 39 | cleanup(); |
| 28 | -$td->report(3); | 40 | +$td->report(11); |
| 29 | 41 | ||
| 30 | sub cleanup | 42 | sub cleanup |
| 31 | { | 43 | { |
| 32 | - unlink "stdout", "stderr"; | 44 | + unlink "stdout", "stderr", "info", "warn", "error", "save", "save2"; |
| 33 | } | 45 | } |
libtests/qtest/logger/2pages.pdf
0 → 100644
No preview for this file type
libtests/qtest/logger/attach.pdf
0 → 100644
No preview for this file type
libtests/qtest/logger/c-exp-error
0 → 100644
| 1 | +qpdfjob json: open missing.pdf: No such file or directory |
libtests/qtest/logger/c-exp-info
0 → 100644
libtests/qtest/logger/c-exp-save
0 → 100644
No preview for this file type
libtests/qtest/logger/c-exp-save2
0 → 100644
libtests/qtest/logger/c-exp-stderr
0 → 100644
libtests/qtest/logger/c-exp-stdout
0 → 100644
libtests/qtest/logger/c-exp-warn
0 → 100644
libtests/qtest/logger/normal.pdf
0 → 100644
| 1 | +%PDF-1.3 | ||
| 2 | +1 0 obj | ||
| 3 | +<< | ||
| 4 | + /Type /Catalog | ||
| 5 | + /Pages 2 0 R | ||
| 6 | +>> | ||
| 7 | +endobj | ||
| 8 | + | ||
| 9 | +2 0 obj | ||
| 10 | +<< | ||
| 11 | + /Type /Pages | ||
| 12 | + /Kids [ | ||
| 13 | + 3 0 R | ||
| 14 | + ] | ||
| 15 | + /Count 1 | ||
| 16 | +>> | ||
| 17 | +endobj | ||
| 18 | + | ||
| 19 | +3 0 obj | ||
| 20 | +<< | ||
| 21 | + /Type /Page | ||
| 22 | + /Parent 2 0 R | ||
| 23 | + /MediaBox [0 0 612 792] | ||
| 24 | + /Contents 4 0 R | ||
| 25 | + /Resources << | ||
| 26 | + /ProcSet 5 0 R | ||
| 27 | + /Font << | ||
| 28 | + /F1 6 0 R | ||
| 29 | + >> | ||
| 30 | + >> | ||
| 31 | +>> | ||
| 32 | +endobj | ||
| 33 | + | ||
| 34 | +4 0 obj | ||
| 35 | +<< | ||
| 36 | + /Length 44 | ||
| 37 | +>> | ||
| 38 | +stream | ||
| 39 | +BT | ||
| 40 | + /F1 24 Tf | ||
| 41 | + 72 720 Td | ||
| 42 | + (Potato) Tj | ||
| 43 | +ET | ||
| 44 | +endstream | ||
| 45 | +endobj | ||
| 46 | + | ||
| 47 | +5 0 obj | ||
| 48 | +[ | ||
| 49 | |||
| 50 | + /Text | ||
| 51 | +] | ||
| 52 | +endobj | ||
| 53 | + | ||
| 54 | +6 0 obj | ||
| 55 | +<< | ||
| 56 | + /Type /Font | ||
| 57 | + /Subtype /Type1 | ||
| 58 | + /Name /F1 | ||
| 59 | + /BaseFont /Helvetica | ||
| 60 | + /Encoding /WinAnsiEncoding | ||
| 61 | +>> | ||
| 62 | +endobj | ||
| 63 | + | ||
| 64 | +xref | ||
| 65 | +0 7 | ||
| 66 | +0000000000 65535 f | ||
| 67 | +0000000009 00000 n | ||
| 68 | +0000000063 00000 n | ||
| 69 | +0000000135 00000 n | ||
| 70 | +0000000307 00000 n | ||
| 71 | +0000000403 00000 n | ||
| 72 | +0000000438 00000 n | ||
| 73 | +trailer << | ||
| 74 | + /Size 7 | ||
| 75 | + /Root 1 0 R | ||
| 76 | +>> | ||
| 77 | +startxref | ||
| 78 | +556 | ||
| 79 | +%%EOF |
libtests/qtest/logger/warning.pdf
0 → 100644
| 1 | +%PDF-1.3 | ||
| 2 | +1 0 obj | ||
| 3 | +<< | ||
| 4 | + /Type /Catalog | ||
| 5 | + /Pages 2 0 R | ||
| 6 | +>> | ||
| 7 | +endobj | ||
| 8 | + | ||
| 9 | +2 0 obj | ||
| 10 | +<< | ||
| 11 | + /Type /Pages | ||
| 12 | + /Kids [ | ||
| 13 | + 3 0 R | ||
| 14 | + ] | ||
| 15 | + /Count 1 | ||
| 16 | +>> | ||
| 17 | +endobj | ||
| 18 | + | ||
| 19 | +3 0 obj | ||
| 20 | +<< | ||
| 21 | + /Type /Page | ||
| 22 | + /Parent 2 0 R | ||
| 23 | + /MediaBox [0 0 612 792] | ||
| 24 | + /Contents 4 0 R | ||
| 25 | + /Resources << | ||
| 26 | + /ProcSet 5 0 R | ||
| 27 | + /Font << | ||
| 28 | + /F1 6 0 R | ||
| 29 | + >> | ||
| 30 | + >> | ||
| 31 | +>> | ||
| 32 | +endobj | ||
| 33 | + | ||
| 34 | +4 0 obj | ||
| 35 | +<< | ||
| 36 | + /Length 44 | ||
| 37 | +>> | ||
| 38 | +stream | ||
| 39 | +BT | ||
| 40 | + /F1 24 Tf | ||
| 41 | + 72 720 Td | ||
| 42 | + (Potato) Tj | ||
| 43 | +ET | ||
| 44 | +endstream | ||
| 45 | +endobj | ||
| 46 | + | ||
| 47 | +5 0 obj | ||
| 48 | +[ | ||
| 49 | |||
| 50 | + /Text | ||
| 51 | +] | ||
| 52 | +endobj | ||
| 53 | + | ||
| 54 | +6 0 obj | ||
| 55 | +<< | ||
| 56 | + /Type /Font | ||
| 57 | + /Subtype /Type1 | ||
| 58 | + /Name /F1 | ||
| 59 | + /BaseFont /Helvetica | ||
| 60 | + /Encoding /WinAnsiEncoding | ||
| 61 | +>> | ||
| 62 | +endobj | ||
| 63 | + | ||
| 64 | +xref | ||
| 65 | +0 7 | ||
| 66 | +0000000000 65535 f | ||
| 67 | +0000000009 00000 n | ||
| 68 | +0000000063 00000 n | ||
| 69 | +0000000135 00000 n | ||
| 70 | +0000000307 00000 n | ||
| 71 | +0000000403 00000 n | ||
| 72 | +0000000438 00000 n | ||
| 73 | +trailer << | ||
| 74 | + /Size 7 | ||
| 75 | + /Root 1 0 R | ||
| 76 | +>> | ||
| 77 | +startxref | ||
| 78 | +1556 | ||
| 79 | +%%EOF |
manual/release-notes.rst
| @@ -158,6 +158,8 @@ For a detailed list of changes, please see the file | @@ -158,6 +158,8 @@ For a detailed list of changes, please see the file | ||
| 158 | output and errors that slipped through the cracks with | 158 | output and errors that slipped through the cracks with |
| 159 | ``setOutputStreams``. | 159 | ``setOutputStreams``. |
| 160 | 160 | ||
| 161 | + - A C API is available in :file:`include/qpdf/qpdflogger-c.h`. | ||
| 162 | + | ||
| 161 | - New methods ``insertItemAndGet``, ``appendItemAndGet``, | 163 | - New methods ``insertItemAndGet``, ``appendItemAndGet``, |
| 162 | ``eraseItemAndGet``, ``replaceKeyAndGet``, and | 164 | ``eraseItemAndGet``, ``replaceKeyAndGet``, and |
| 163 | ``removeKeyAndGet`` return the newly added or removed object. | 165 | ``removeKeyAndGet`` return the newly added or removed object. |