Commit 8130d50e3b5aa0235a133c3c5a3018ac01afb5e1
1 parent
daef4e8f
Add C API to QPDFLogger
Showing
23 changed files
with
592 additions
and
15 deletions
ChangeLog
| 1 | 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 | 9 | * Add additional qpdfjob C API functions take a handle. |
| 4 | 10 | |
| 5 | 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 | 130 | void setError(std::shared_ptr<Pipeline>); |
| 131 | 131 | // See notes above about the save pipeline |
| 132 | 132 | QPDF_DLL |
| 133 | - void setSave(std::shared_ptr<Pipeline>); | |
| 133 | + void setSave(std::shared_ptr<Pipeline>, bool only_if_not_set); | |
| 134 | 134 | QPDF_DLL |
| 135 | - void saveToStandardOutput(); | |
| 135 | + void saveToStandardOutput(bool only_if_not_set); | |
| 136 | 136 | |
| 137 | 137 | // Shortcut for logic to reset output to new output/error streams. |
| 138 | 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
libqpdf/QPDFJob.cc
| ... | ... | @@ -710,7 +710,7 @@ QPDFJob::checkConfiguration() |
| 710 | 710 | save_to_stdout = true; |
| 711 | 711 | } |
| 712 | 712 | if (save_to_stdout) { |
| 713 | - this->m->log->saveToStandardOutput(); | |
| 713 | + this->m->log->saveToStandardOutput(true); | |
| 714 | 714 | } |
| 715 | 715 | if ((!m->split_pages) && |
| 716 | 716 | QUtil::same_file(m->infilename.get(), m->outfilename.get())) { |
| ... | ... | @@ -925,7 +925,7 @@ QPDFJob::doShowObj(QPDF& pdf) |
| 925 | 925 | } else { |
| 926 | 926 | // If anything has been written to standard output, |
| 927 | 927 | // this will fail. |
| 928 | - this->m->log->saveToStandardOutput(); | |
| 928 | + this->m->log->saveToStandardOutput(true); | |
| 929 | 929 | obj.pipeStreamData( |
| 930 | 930 | this->m->log->getSave().get(), |
| 931 | 931 | (filter && m->normalize) ? qpdf_ef_normalize : 0, |
| ... | ... | @@ -1031,7 +1031,7 @@ QPDFJob::doShowAttachment(QPDF& pdf) |
| 1031 | 1031 | auto efs = fs->getEmbeddedFileStream(); |
| 1032 | 1032 | // saveToStandardOutput has already been called, but it's harmless |
| 1033 | 1033 | // to call it again, so do as defensive coding. |
| 1034 | - this->m->log->saveToStandardOutput(); | |
| 1034 | + this->m->log->saveToStandardOutput(true); | |
| 1035 | 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 | 3289 | } else { |
| 3290 | 3290 | // saveToStandardOutput has already been called, but |
| 3291 | 3291 | // calling it again is defensive and harmless. |
| 3292 | - this->m->log->saveToStandardOutput(); | |
| 3292 | + this->m->log->saveToStandardOutput(true); | |
| 3293 | 3293 | w.setOutputPipeline(this->m->log->getSave().get()); |
| 3294 | 3294 | } |
| 3295 | 3295 | setWriterOptions(pdf, w); | ... | ... |
libqpdf/QPDFLogger.cc
| ... | ... | @@ -181,8 +181,11 @@ QPDFLogger::setError(std::shared_ptr<Pipeline> p) |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | 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 | 189 | if (this->m->p_save == p) { |
| 187 | 190 | return; |
| 188 | 191 | } |
| ... | ... | @@ -202,9 +205,9 @@ QPDFLogger::setSave(std::shared_ptr<Pipeline> p) |
| 202 | 205 | } |
| 203 | 206 | |
| 204 | 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 | 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 | 33 | runlength |
| 34 | 34 | sha2 |
| 35 | 35 | sparse_array) |
| 36 | +set(TEST_C_PROGRAMS | |
| 37 | + logger_c) | |
| 38 | + | |
| 36 | 39 | foreach(PROG ${TEST_PROGRAMS}) |
| 37 | 40 | add_executable(${PROG} ${PROG}.cc) |
| 38 | 41 | target_link_libraries(${PROG} libqpdf_object) |
| 39 | 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 | 49 | # Since libtests link with the object library and don't use the DLL, |
| 42 | 50 | # we don't need to (and shouldn't) add the libqpdf target directory to | ... | ... |
libtests/logger.cc
| ... | ... | @@ -22,7 +22,7 @@ test1() |
| 22 | 22 | *(logger->getInfo()) << "getSave exception: " << e.what() << "\n"; |
| 23 | 23 | } |
| 24 | 24 | try { |
| 25 | - logger->saveToStandardOutput(); | |
| 25 | + logger->saveToStandardOutput(true); | |
| 26 | 26 | assert(false); |
| 27 | 27 | } catch (std::logic_error& e) { |
| 28 | 28 | *(logger->getInfo()) |
| ... | ... | @@ -40,12 +40,12 @@ test2() |
| 40 | 40 | // First call saveToStandardOutput. Then use info, which then to |
| 41 | 41 | // go stderr. |
| 42 | 42 | QPDFLogger l; |
| 43 | - l.saveToStandardOutput(); | |
| 43 | + l.saveToStandardOutput(true); | |
| 44 | 44 | l.info(std::string("info to stderr\n")); |
| 45 | 45 | *(l.getSave()) << "save to stdout\n"; |
| 46 | 46 | l.setInfo(nullptr); |
| 47 | 47 | l.info("info still to stderr\n"); |
| 48 | - l.setSave(nullptr); | |
| 48 | + l.setSave(nullptr, false); | |
| 49 | 49 | l.setInfo(nullptr); |
| 50 | 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 | 24 | {$td->FILE => "exp-stderr"}, |
| 25 | 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 | 39 | cleanup(); |
| 28 | -$td->report(3); | |
| 40 | +$td->report(11); | |
| 29 | 41 | |
| 30 | 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 | 158 | output and errors that slipped through the cracks with |
| 159 | 159 | ``setOutputStreams``. |
| 160 | 160 | |
| 161 | + - A C API is available in :file:`include/qpdf/qpdflogger-c.h`. | |
| 162 | + | |
| 161 | 163 | - New methods ``insertItemAndGet``, ``appendItemAndGet``, |
| 162 | 164 | ``eraseItemAndGet``, ``replaceKeyAndGet``, and |
| 163 | 165 | ``removeKeyAndGet`` return the newly added or removed object. | ... | ... |