blob: f82223b91dd8180883ede922083b33a7844a667f [file] [log] [blame]
Radek Krejcid3ca0632019-04-16 16:54:54 +02001/**
Michal Vaskoafac7822020-10-20 14:22:26 +02002 * @file out.c
Radek Krejcid3ca0632019-04-16 16:54:54 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoafac7822020-10-20 14:22:26 +02004 * @brief libyang output functions.
Radek Krejcid3ca0632019-04-16 16:54:54 +02005 *
Michal Vaskoafac7822020-10-20 14:22:26 +02006 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
Radek Krejcid3ca0632019-04-16 16:54:54 +02007 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, vdprintf */
Radek Krejcid3ca0632019-04-16 16:54:54 +020017
Michal Vaskoafac7822020-10-20 14:22:26 +020018#include "out.h"
19#include "out_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020020
21#include <assert.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020022#include <errno.h>
23#include <stdarg.h>
Radek Krejci47fab892020-11-05 17:02:41 +010024#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include <stdio.h>
26#include <stdlib.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020027#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include <unistd.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020029
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020031#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "log.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020033#include "printer_data.h"
34#include "printer_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010035#include "tree_data.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "tree_schema.h"
Radek Krejcid3ca0632019-04-16 16:54:54 +020037
38/**
39 * @brief informational structure shared by printers
40 */
41struct ext_substmt_info_s ext_substmt_info[] = {
Radek Krejci0f969882020-08-21 16:56:47 +020042 {NULL, NULL, 0}, /**< LYEXT_SUBSTMT_SELF */
43 {"argument", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ARGUMENT */
44 {"base", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BASE */
45 {"belongs-to", "module", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BELONGSTO */
46 {"contact", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_CONTACT */
47 {"default", "value", 0}, /**< LYEXT_SUBSTMT_DEFAULT */
48 {"description", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_DESCRIPTION */
49 {"error-app-tag", "value", 0}, /**< LYEXT_SUBSTMT_ERRTAG */
50 {"error-message", "value", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ERRMSG */
51 {"key", "value", 0}, /**< LYEXT_SUBSTMT_KEY */
52 {"namespace", "uri", 0}, /**< LYEXT_SUBSTMT_NAMESPACE */
53 {"organization", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ORGANIZATION */
54 {"path", "value", 0}, /**< LYEXT_SUBSTMT_PATH */
55 {"prefix", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_PREFIX */
56 {"presence", "value", 0}, /**< LYEXT_SUBSTMT_PRESENCE */
57 {"reference", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_REFERENCE */
58 {"revision-date", "date", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REVISIONDATE */
59 {"units", "name", 0}, /**< LYEXT_SUBSTMT_UNITS */
60 {"value", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VALUE */
61 {"yang-version", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VERSION */
62 {"modifier", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MODIFIER */
63 {"require-instance", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REQINST */
64 {"yin-element", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_YINELEM */
65 {"config", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_CONFIG */
66 {"mandatory", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MANDATORY */
67 {"ordered-by", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ORDEREDBY */
68 {"status", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_STATUS */
69 {"fraction-digits", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_DIGITS */
70 {"max-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MAX */
71 {"min-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MIN */
72 {"position", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_POSITION */
73 {"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
Radek Krejcid3ca0632019-04-16 16:54:54 +020074};
75
Radek Krejci857189e2020-09-01 13:26:36 +020076ly_bool
Radek Krejci1deb5be2020-08-26 16:43:36 +020077ly_should_print(const struct lyd_node *node, uint32_t options)
Michal Vasko9b368d32020-02-14 13:53:31 +010078{
Michal Vasko5be03d62020-12-09 18:08:39 +010079 const struct lyd_node *elem, *op;
Michal Vasko9b368d32020-02-14 13:53:31 +010080
Radek Krejci7931b192020-06-25 17:05:03 +020081 if (options & LYD_PRINT_WD_TRIM) {
Michal Vasko9b368d32020-02-14 13:53:31 +010082 /* do not print default nodes */
83 if (node->flags & LYD_DEFAULT) {
84 /* implicit default node/NP container with only default nodes */
85 return 0;
86 } else if (node->schema->nodetype & LYD_NODE_TERM) {
Radek Krejci19611252020-10-04 13:54:53 +020087 if (lyd_is_default(node)) {
Michal Vasko9b368d32020-02-14 13:53:31 +010088 /* explicit default node */
89 return 0;
90 }
91 }
Michal Vasko5be03d62020-12-09 18:08:39 +010092 } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK)) {
93 /* LYD_PRINT_WD_EXPLICIT, find out if this is some input/output */
94 for (op = node; op && (op->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = lyd_parent(op)) {}
95
96 if (!op && (node->schema->flags & LYS_CONFIG_W)) {
97 /* print only if it contains status data in its subtree */
98 LYD_TREE_DFS_BEGIN(node, elem) {
99 if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
100 if (elem->schema->flags & LYS_CONFIG_R) {
101 return 1;
102 }
Michal Vaskodb4f9e42020-06-01 17:29:56 +0200103 }
Michal Vasko5be03d62020-12-09 18:08:39 +0100104 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100105 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100106 }
107 return 0;
Radek Krejci7931b192020-06-25 17:05:03 +0200108 } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYD_PRINT_KEEPEMPTYCONT)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100109 /* avoid empty default containers */
Michal Vasko56daf732020-08-10 10:57:18 +0200110 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100111 if (elem->schema->nodetype != LYS_CONTAINER) {
112 return 1;
113 }
114 assert(elem->flags & LYD_DEFAULT);
Michal Vasko56daf732020-08-10 10:57:18 +0200115 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100116 }
117 return 0;
118 }
119
120 return 1;
121}
122
Radek Krejci241f6b52020-05-21 18:13:49 +0200123API LY_OUT_TYPE
124ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100125{
Radek Krejci241f6b52020-05-21 18:13:49 +0200126 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100127 return out->type;
128}
129
Radek Krejci84ce7b12020-06-11 17:28:25 +0200130API LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200131ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100132{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200133 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100134
Radek Krejci84ce7b12020-06-11 17:28:25 +0200135 *out = calloc(1, sizeof **out);
136 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100137
Radek Krejci84ce7b12020-06-11 17:28:25 +0200138 (*out)->type = LY_OUT_CALLBACK;
139 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200140 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100141
Radek Krejci84ce7b12020-06-11 17:28:25 +0200142 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100143}
144
Michal Vasko69730152020-10-09 16:30:07 +0200145API ly_write_clb
146ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100147{
148 void *prev_clb;
149
Radek Krejci241f6b52020-05-21 18:13:49 +0200150 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100151
152 prev_clb = out->method.clb.func;
153
154 if (writeclb) {
155 out->method.clb.func = writeclb;
156 }
157
158 return prev_clb;
159}
160
161API void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200162ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100163{
164 void *prev_arg;
165
Radek Krejci241f6b52020-05-21 18:13:49 +0200166 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100167
168 prev_arg = out->method.clb.arg;
169
170 if (arg) {
171 out->method.clb.arg = arg;
172 }
173
174 return prev_arg;
175}
176
Radek Krejci84ce7b12020-06-11 17:28:25 +0200177API LY_ERR
178ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100179{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200180 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100181
Radek Krejci84ce7b12020-06-11 17:28:25 +0200182 *out = calloc(1, sizeof **out);
183 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200184 (*out)->type = LY_OUT_FD;
185 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100186
Radek Krejci84ce7b12020-06-11 17:28:25 +0200187 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100188}
189
190API int
Radek Krejci241f6b52020-05-21 18:13:49 +0200191ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100192{
193 int prev_fd;
194
Radek Krejci241f6b52020-05-21 18:13:49 +0200195 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100196
Radek Krejci241f6b52020-05-21 18:13:49 +0200197 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100198 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200199 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100200 prev_fd = out->method.fd;
201 }
202
203 if (fd != -1) {
204 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200205 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100206 int streamfd;
207 FILE *stream;
208
209 streamfd = dup(fd);
210 if (streamfd < 0) {
211 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
212 return -1;
213 }
214 stream = fdopen(streamfd, "a");
215 if (!stream) {
216 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
217 close(streamfd);
218 return -1;
219 }
220 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
221 fclose(out->method.fdstream.f);
222 out->method.fdstream.f = stream;
223 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200224 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100225 out->method.fd = fd;
226 }
227 }
228
229 return prev_fd;
230}
231
Radek Krejci84ce7b12020-06-11 17:28:25 +0200232API LY_ERR
233ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100234{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200235 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100236
Radek Krejci84ce7b12020-06-11 17:28:25 +0200237 *out = calloc(1, sizeof **out);
238 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100239
Radek Krejci84ce7b12020-06-11 17:28:25 +0200240 (*out)->type = LY_OUT_FILE;
241 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100242
Radek Krejci84ce7b12020-06-11 17:28:25 +0200243 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100244}
245
246API FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200247ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100248{
249 FILE *prev_f;
250
Radek Krejci241f6b52020-05-21 18:13:49 +0200251 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100252
253 prev_f = out->method.f;
254
255 if (f) {
256 out->method.f = f;
257 }
258
259 return prev_f;
260}
261
Radek Krejci84ce7b12020-06-11 17:28:25 +0200262API LY_ERR
263ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100264{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200265 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100266
Radek Krejci84ce7b12020-06-11 17:28:25 +0200267 *out = calloc(1, sizeof **out);
268 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100269
Radek Krejci84ce7b12020-06-11 17:28:25 +0200270 (*out)->type = LY_OUT_MEMORY;
271 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100272 if (!size) {
273 /* buffer is supposed to be allocated */
274 *strp = NULL;
275 } else if (*strp) {
276 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200277 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100278 }
279
Radek Krejci84ce7b12020-06-11 17:28:25 +0200280 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100281}
282
283char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200284ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100285{
286 char *data;
287
Radek Krejci241f6b52020-05-21 18:13:49 +0200288 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100289
290 data = *out->method.mem.buf;
291
292 if (strp) {
293 out->method.mem.buf = strp;
294 out->method.mem.len = out->method.mem.size = 0;
295 out->printed = 0;
296 if (!size) {
297 /* buffer is supposed to be allocated */
298 *strp = NULL;
299 } else if (*strp) {
300 /* there is already buffer to use */
301 out->method.mem.size = size;
302 }
303 }
304
305 return data;
306}
307
308API LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200309ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100310{
311 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
312
Michal Vaskod989ba02020-08-24 10:59:24 +0200313 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200314 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100315 LOGINT(NULL);
316 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200317 case LY_OUT_FD:
Michal Vasko69730152020-10-09 16:30:07 +0200318 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100319 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
320 return LY_ESYS;
321 }
Michal Vasko69730152020-10-09 16:30:07 +0200322 if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200323 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
324 return LY_ESYS;
325 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100326 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200327 case LY_OUT_FDSTREAM:
328 case LY_OUT_FILE:
329 case LY_OUT_FILEPATH:
Michal Vasko69730152020-10-09 16:30:07 +0200330 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100331 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
332 return LY_ESYS;
333 }
Michal Vasko69730152020-10-09 16:30:07 +0200334 if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200335 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
336 return LY_ESYS;
337 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100338 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200339 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200340 if (out->method.mem.buf && *out->method.mem.buf) {
341 memset(*out->method.mem.buf, 0, out->method.mem.len);
342 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100343 out->printed = 0;
344 out->method.mem.len = 0;
345 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200346 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100347 /* nothing to do (not seekable) */
348 break;
349 }
350
351 return LY_SUCCESS;
352}
353
Radek Krejci84ce7b12020-06-11 17:28:25 +0200354API LY_ERR
355ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100356{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200357 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100358
Radek Krejci84ce7b12020-06-11 17:28:25 +0200359 *out = calloc(1, sizeof **out);
360 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100361
Radek Krejci84ce7b12020-06-11 17:28:25 +0200362 (*out)->type = LY_OUT_FILEPATH;
363 (*out)->method.fpath.f = fopen(filepath, "w");
364 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100365 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200366 free(*out);
367 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200368 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100369 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200370 (*out)->method.fpath.filepath = strdup(filepath);
371 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100372}
373
374API const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200375ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100376{
377 FILE *f;
378
Radek Krejci241f6b52020-05-21 18:13:49 +0200379 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100380
381 if (!filepath) {
382 return out->method.fpath.filepath;
383 }
384
385 /* replace filepath */
386 f = out->method.fpath.f;
387 out->method.fpath.f = fopen(filepath, "w");
388 if (!out->method.fpath.f) {
389 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
390 out->method.fpath.f = f;
Michal Vasko69730152020-10-09 16:30:07 +0200391 return (void *)-1;
Radek Krejcia5bba312020-01-09 15:41:20 +0100392 }
393 fclose(f);
394 free(out->method.fpath.filepath);
395 out->method.fpath.filepath = strdup(filepath);
396
397 return NULL;
398}
399
400API void
Radek Krejci857189e2020-09-01 13:26:36 +0200401ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100402{
403 if (!out) {
404 return;
405 }
406
407 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200408 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100409 if (clb_arg_destructor) {
410 clb_arg_destructor(out->method.clb.arg);
411 }
412 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200413 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100414 fclose(out->method.fdstream.f);
415 if (destroy) {
416 close(out->method.fdstream.fd);
417 }
418 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200419 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100420 if (destroy) {
421 close(out->method.fd);
422 }
423 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200424 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100425 if (destroy) {
426 fclose(out->method.f);
427 }
428 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200429 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100430 if (destroy) {
431 free(*out->method.mem.buf);
432 }
433 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200434 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100435 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200436 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100437 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200438 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100439 LOGINT(NULL);
440 }
Michal Vasko159b8872020-11-18 18:14:16 +0100441
442 free(out->buffered);
Radek Krejcia5bba312020-01-09 15:41:20 +0100443 free(out);
444}
445
Michal Vasko5233e962020-08-14 14:26:20 +0200446static LY_ERR
447ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200448{
Michal Vasko5233e962020-08-14 14:26:20 +0200449 LY_ERR ret;
450 int written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200451 char *msg = NULL, *aux;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200452
453 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200454 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200455 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200456 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200457 case LY_OUT_FDSTREAM:
458 case LY_OUT_FILEPATH:
459 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200460 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200461 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200462 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200463 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200464 break;
465 }
Michal Vasko5233e962020-08-14 14:26:20 +0200466 if (out->method.mem.len + written + 1 > out->method.mem.size) {
467 aux = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200468 if (!aux) {
469 out->method.mem.buf = NULL;
470 out->method.mem.len = 0;
471 out->method.mem.size = 0;
472 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200473 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200474 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100475 *out->method.mem.buf = aux;
Michal Vasko5233e962020-08-14 14:26:20 +0200476 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200477 }
Michal Vasko5233e962020-08-14 14:26:20 +0200478 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
479 out->method.mem.len += written;
Radek Krejcia5bba312020-01-09 15:41:20 +0100480 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejcid3ca0632019-04-16 16:54:54 +0200481 free(msg);
482 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200483 case LY_OUT_CALLBACK:
Michal Vasko5233e962020-08-14 14:26:20 +0200484 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200485 break;
486 }
Michal Vasko5233e962020-08-14 14:26:20 +0200487 written = out->method.clb.func(out->method.clb.arg, msg, written);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200488 free(msg);
489 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200490 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100491 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200492 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200493 }
494
Michal Vasko5233e962020-08-14 14:26:20 +0200495 if (written < 0) {
496 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
497 written = 0;
498 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200499 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200500 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100501 /* move the original file descriptor to the end of the output file */
502 lseek(out->method.fdstream.fd, 0, SEEK_END);
503 }
Michal Vasko5233e962020-08-14 14:26:20 +0200504 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200505 }
Michal Vasko5233e962020-08-14 14:26:20 +0200506
507 out->printed += written;
508 out->func_printed += written;
509 return ret;
510}
511
512LY_ERR
513ly_print_(struct ly_out *out, const char *format, ...)
514{
515 LY_ERR ret;
516 va_list ap;
517
518 va_start(ap, format);
519 ret = ly_vprint_(out, format, ap);
520 va_end(ap);
521
522 return ret;
523}
524
525API LY_ERR
526ly_print(struct ly_out *out, const char *format, ...)
527{
528 LY_ERR ret;
529 va_list ap;
530
531 out->func_printed = 0;
532
533 va_start(ap, format);
534 ret = ly_vprint_(out, format, ap);
535 va_end(ap);
536
537 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200538}
539
Radek Krejci2aae3752020-05-27 18:16:30 +0200540API void
Radek Krejci241f6b52020-05-21 18:13:49 +0200541ly_print_flush(struct ly_out *out)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200542{
543 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200544 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100545 /* move the original file descriptor to the end of the output file */
546 lseek(out->method.fdstream.fd, 0, SEEK_END);
547 fflush(out->method.fdstream.f);
548 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200549 case LY_OUT_FILEPATH:
550 case LY_OUT_FILE:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200551 fflush(out->method.f);
552 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200553 case LY_OUT_FD:
Radek Krejcie7b95092019-05-15 11:03:07 +0200554 fsync(out->method.fd);
555 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200556 case LY_OUT_MEMORY:
557 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200558 /* nothing to do */
559 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200560 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100561 LOGINT(NULL);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200562 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200563
564 free(out->buffered);
565 out->buf_size = out->buf_len = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200566}
567
Michal Vasko5233e962020-08-14 14:26:20 +0200568LY_ERR
569ly_write_(struct ly_out *out, const char *buf, size_t len)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200570{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200571 LY_ERR ret = LY_SUCCESS;
572 size_t written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200573
574 if (out->hole_count) {
575 /* we are buffering data after a hole */
Radek Krejcie7b95092019-05-15 11:03:07 +0200576 if (out->buf_len + len > out->buf_size) {
577 out->buffered = ly_realloc(out->buffered, out->buf_len + len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200578 if (!out->buffered) {
579 out->buf_len = 0;
580 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200581 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200582 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200583 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200584 out->buf_size = out->buf_len + len;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200585 }
586
Radek Krejcie7b95092019-05-15 11:03:07 +0200587 memcpy(&out->buffered[out->buf_len], buf, len);
588 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200589
590 out->printed += len;
591 out->func_printed += len;
592 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200593 }
594
Radek Krejci897ad2e2019-04-29 16:43:07 +0200595repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200596 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200597 case LY_OUT_MEMORY:
Radek Krejcie7b95092019-05-15 11:03:07 +0200598 if (out->method.mem.len + len + 1 > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100599 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + len + 1);
600 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200601 out->method.mem.len = 0;
602 out->method.mem.size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200603 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200604 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200605 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200606 out->method.mem.size = out->method.mem.len + len + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200607 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100608 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200609 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100610 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200611
Michal Vasko5233e962020-08-14 14:26:20 +0200612 written = len;
613 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200614 case LY_OUT_FD: {
615 ssize_t r;
616 r = write(out->method.fd, buf, len);
617 if (r < 0) {
618 ret = LY_ESYS;
619 } else {
620 written = (size_t)r;
621 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200622 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200623 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200624 case LY_OUT_FDSTREAM:
625 case LY_OUT_FILEPATH:
626 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200627 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200628 if (written != len) {
629 ret = LY_ESYS;
630 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200631 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200632 case LY_OUT_CALLBACK: {
633 ssize_t r;
634 r = out->method.clb.func(out->method.clb.arg, buf, len);
635 if (r < 0) {
636 ret = LY_ESYS;
637 } else {
638 written = (size_t)r;
639 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200640 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200641 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200642 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100643 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200644 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200645 }
646
Radek Krejci1deb5be2020-08-26 16:43:36 +0200647 if (ret) {
Michal Vasko69730152020-10-09 16:30:07 +0200648 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200649 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200650 goto repeat;
651 }
Michal Vasko5233e962020-08-14 14:26:20 +0200652 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
653 written = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200654 } else if ((size_t)written != len) {
Michal Vasko5233e962020-08-14 14:26:20 +0200655 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__,
Michal Vasko69730152020-10-09 16:30:07 +0200656 len - (size_t)written, len);
Michal Vasko5233e962020-08-14 14:26:20 +0200657 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200658 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200659 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100660 /* move the original file descriptor to the end of the output file */
661 lseek(out->method.fdstream.fd, 0, SEEK_END);
662 }
Michal Vasko5233e962020-08-14 14:26:20 +0200663 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200664 }
Michal Vasko5233e962020-08-14 14:26:20 +0200665
666 out->printed += written;
667 out->func_printed += written;
668 return ret;
669}
670
671API LY_ERR
672ly_write(struct ly_out *out, const char *buf, size_t len)
673{
674 out->func_printed = 0;
675
676 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200677}
678
Michal Vasko63f3d842020-07-08 10:10:14 +0200679API size_t
680ly_out_printed(const struct ly_out *out)
681{
682 return out->func_printed;
683}
684
Michal Vasko5233e962020-08-14 14:26:20 +0200685LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200686ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200687{
688 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200689 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200690 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100691 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
692 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200693 out->method.mem.len = 0;
694 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200695 LOGMEM(NULL);
696 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200697 }
698 out->method.mem.size = out->method.mem.len + count;
699 }
700
701 /* save the current position */
702 *position = out->method.mem.len;
703
704 /* skip the memory */
705 out->method.mem.len += count;
706 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200707 case LY_OUT_FD:
708 case LY_OUT_FDSTREAM:
709 case LY_OUT_FILEPATH:
710 case LY_OUT_FILE:
711 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200712 /* buffer the hole */
713 if (out->buf_len + count > out->buf_size) {
714 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
715 if (!out->buffered) {
716 out->buf_len = 0;
717 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200718 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200719 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200720 }
721 out->buf_size = out->buf_len + count;
722 }
723
724 /* save the current position */
725 *position = out->buf_len;
726
727 /* skip the memory */
728 out->buf_len += count;
729
730 /* increase hole counter */
731 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100732 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200733 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100734 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200735 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200736 }
737
Michal Vasko5233e962020-08-14 14:26:20 +0200738 /* update printed bytes counter despite we actually printed just a hole */
739 out->printed += count;
740 out->func_printed += count;
741 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200742}
743
Michal Vasko66d99972020-06-29 13:37:42 +0200744LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200745ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200746{
Michal Vasko66d99972020-06-29 13:37:42 +0200747 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200748
749 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200750 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200751 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100752 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200753 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200754 case LY_OUT_FD:
755 case LY_OUT_FDSTREAM:
756 case LY_OUT_FILEPATH:
757 case LY_OUT_FILE:
758 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200759 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200760 LOGMEM(NULL);
761 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200762 }
763
764 /* write into the hole */
765 memcpy(&out->buffered[position], buf, count);
766
767 /* decrease hole counter */
768 --out->hole_count;
769
770 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200771 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200772 * printed bytes counter is updated by ly_write_() */
773 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200774 out->buf_len = 0;
775 }
776 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200777 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200778 LOGINT(NULL);
779 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200780 }
781
Radek Krejci241f6b52020-05-21 18:13:49 +0200782 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100783 /* move the original file descriptor to the end of the output file */
784 lseek(out->method.fdstream.fd, 0, SEEK_END);
785 }
Michal Vasko66d99972020-06-29 13:37:42 +0200786 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200787}