blob: 13f462bbe71457fc7ec067216f5ae631317ff3b8 [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 Krejcid3ca0632019-04-16 16:54:54 +020016
Michal Vaskoafac7822020-10-20 14:22:26 +020017#include "out.h"
18#include "out_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020019
20#include <assert.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020021#include <errno.h>
22#include <stdarg.h>
Radek Krejci47fab892020-11-05 17:02:41 +010023#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include <stdio.h>
25#include <stdlib.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020026#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include <unistd.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020028
Radek Krejci535ea9f2020-05-29 16:01:05 +020029#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020030#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "log.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020032#include "printer_data.h"
33#include "printer_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010034#include "tree_data.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "tree_schema.h"
Radek Krejcid3ca0632019-04-16 16:54:54 +020036
37/**
38 * @brief informational structure shared by printers
39 */
40struct ext_substmt_info_s ext_substmt_info[] = {
Radek Krejci0f969882020-08-21 16:56:47 +020041 {NULL, NULL, 0}, /**< LYEXT_SUBSTMT_SELF */
42 {"argument", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ARGUMENT */
43 {"base", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BASE */
44 {"belongs-to", "module", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BELONGSTO */
45 {"contact", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_CONTACT */
46 {"default", "value", 0}, /**< LYEXT_SUBSTMT_DEFAULT */
47 {"description", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_DESCRIPTION */
48 {"error-app-tag", "value", 0}, /**< LYEXT_SUBSTMT_ERRTAG */
49 {"error-message", "value", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ERRMSG */
50 {"key", "value", 0}, /**< LYEXT_SUBSTMT_KEY */
51 {"namespace", "uri", 0}, /**< LYEXT_SUBSTMT_NAMESPACE */
52 {"organization", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ORGANIZATION */
53 {"path", "value", 0}, /**< LYEXT_SUBSTMT_PATH */
54 {"prefix", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_PREFIX */
55 {"presence", "value", 0}, /**< LYEXT_SUBSTMT_PRESENCE */
56 {"reference", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_REFERENCE */
57 {"revision-date", "date", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REVISIONDATE */
58 {"units", "name", 0}, /**< LYEXT_SUBSTMT_UNITS */
59 {"value", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VALUE */
60 {"yang-version", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VERSION */
61 {"modifier", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MODIFIER */
62 {"require-instance", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REQINST */
63 {"yin-element", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_YINELEM */
64 {"config", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_CONFIG */
65 {"mandatory", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MANDATORY */
66 {"ordered-by", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ORDEREDBY */
67 {"status", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_STATUS */
68 {"fraction-digits", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_DIGITS */
69 {"max-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MAX */
70 {"min-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MIN */
71 {"position", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_POSITION */
72 {"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
Radek Krejcid3ca0632019-04-16 16:54:54 +020073};
74
Radek Krejci857189e2020-09-01 13:26:36 +020075ly_bool
Radek Krejci1deb5be2020-08-26 16:43:36 +020076ly_should_print(const struct lyd_node *node, uint32_t options)
Michal Vasko9b368d32020-02-14 13:53:31 +010077{
Michal Vasko56daf732020-08-10 10:57:18 +020078 const struct lyd_node *elem;
Michal Vasko9b368d32020-02-14 13:53:31 +010079
Radek Krejci7931b192020-06-25 17:05:03 +020080 if (options & LYD_PRINT_WD_TRIM) {
Michal Vasko9b368d32020-02-14 13:53:31 +010081 /* do not print default nodes */
82 if (node->flags & LYD_DEFAULT) {
83 /* implicit default node/NP container with only default nodes */
84 return 0;
85 } else if (node->schema->nodetype & LYD_NODE_TERM) {
Radek Krejci19611252020-10-04 13:54:53 +020086 if (lyd_is_default(node)) {
Michal Vasko9b368d32020-02-14 13:53:31 +010087 /* explicit default node */
88 return 0;
89 }
90 }
Radek Krejci7931b192020-06-25 17:05:03 +020091 } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
Radek Krejci241f6b52020-05-21 18:13:49 +020092 /* LYDP_WD_EXPLICIT
Michal Vasko9b368d32020-02-14 13:53:31 +010093 * - print only if it contains status data in its subtree */
Michal Vasko56daf732020-08-10 10:57:18 +020094 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vaskodb4f9e42020-06-01 17:29:56 +020095 if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
96 if (elem->schema->flags & LYS_CONFIG_R) {
97 return 1;
98 }
Michal Vasko9b368d32020-02-14 13:53:31 +010099 }
Michal Vasko56daf732020-08-10 10:57:18 +0200100 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100101 }
102 return 0;
Radek Krejci7931b192020-06-25 17:05:03 +0200103 } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYD_PRINT_KEEPEMPTYCONT)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100104 /* avoid empty default containers */
Michal Vasko56daf732020-08-10 10:57:18 +0200105 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100106 if (elem->schema->nodetype != LYS_CONTAINER) {
107 return 1;
108 }
109 assert(elem->flags & LYD_DEFAULT);
Michal Vasko56daf732020-08-10 10:57:18 +0200110 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100111 }
112 return 0;
113 }
114
115 return 1;
116}
117
Radek Krejci241f6b52020-05-21 18:13:49 +0200118API LY_OUT_TYPE
119ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100120{
Radek Krejci241f6b52020-05-21 18:13:49 +0200121 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100122 return out->type;
123}
124
Radek Krejci84ce7b12020-06-11 17:28:25 +0200125API LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200126ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100127{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200128 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100129
Radek Krejci84ce7b12020-06-11 17:28:25 +0200130 *out = calloc(1, sizeof **out);
131 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100132
Radek Krejci84ce7b12020-06-11 17:28:25 +0200133 (*out)->type = LY_OUT_CALLBACK;
134 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200135 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100136
Radek Krejci84ce7b12020-06-11 17:28:25 +0200137 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100138}
139
Michal Vasko69730152020-10-09 16:30:07 +0200140API ly_write_clb
141ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100142{
143 void *prev_clb;
144
Radek Krejci241f6b52020-05-21 18:13:49 +0200145 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100146
147 prev_clb = out->method.clb.func;
148
149 if (writeclb) {
150 out->method.clb.func = writeclb;
151 }
152
153 return prev_clb;
154}
155
156API void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200157ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100158{
159 void *prev_arg;
160
Radek Krejci241f6b52020-05-21 18:13:49 +0200161 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100162
163 prev_arg = out->method.clb.arg;
164
165 if (arg) {
166 out->method.clb.arg = arg;
167 }
168
169 return prev_arg;
170}
171
Radek Krejci84ce7b12020-06-11 17:28:25 +0200172API LY_ERR
173ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100174{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200175 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100176
Radek Krejci84ce7b12020-06-11 17:28:25 +0200177 *out = calloc(1, sizeof **out);
178 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200179 (*out)->type = LY_OUT_FD;
180 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100181
Radek Krejci84ce7b12020-06-11 17:28:25 +0200182 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100183}
184
185API int
Radek Krejci241f6b52020-05-21 18:13:49 +0200186ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100187{
188 int prev_fd;
189
Radek Krejci241f6b52020-05-21 18:13:49 +0200190 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100191
Radek Krejci241f6b52020-05-21 18:13:49 +0200192 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100193 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200194 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100195 prev_fd = out->method.fd;
196 }
197
198 if (fd != -1) {
199 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200200 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100201 int streamfd;
202 FILE *stream;
203
204 streamfd = dup(fd);
205 if (streamfd < 0) {
206 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
207 return -1;
208 }
209 stream = fdopen(streamfd, "a");
210 if (!stream) {
211 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
212 close(streamfd);
213 return -1;
214 }
215 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
216 fclose(out->method.fdstream.f);
217 out->method.fdstream.f = stream;
218 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200219 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100220 out->method.fd = fd;
221 }
222 }
223
224 return prev_fd;
225}
226
Radek Krejci84ce7b12020-06-11 17:28:25 +0200227API LY_ERR
228ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100229{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200230 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100231
Radek Krejci84ce7b12020-06-11 17:28:25 +0200232 *out = calloc(1, sizeof **out);
233 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100234
Radek Krejci84ce7b12020-06-11 17:28:25 +0200235 (*out)->type = LY_OUT_FILE;
236 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100237
Radek Krejci84ce7b12020-06-11 17:28:25 +0200238 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100239}
240
241API FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200242ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100243{
244 FILE *prev_f;
245
Radek Krejci241f6b52020-05-21 18:13:49 +0200246 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100247
248 prev_f = out->method.f;
249
250 if (f) {
251 out->method.f = f;
252 }
253
254 return prev_f;
255}
256
Radek Krejci84ce7b12020-06-11 17:28:25 +0200257API LY_ERR
258ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100259{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200260 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100261
Radek Krejci84ce7b12020-06-11 17:28:25 +0200262 *out = calloc(1, sizeof **out);
263 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100264
Radek Krejci84ce7b12020-06-11 17:28:25 +0200265 (*out)->type = LY_OUT_MEMORY;
266 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100267 if (!size) {
268 /* buffer is supposed to be allocated */
269 *strp = NULL;
270 } else if (*strp) {
271 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200272 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100273 }
274
Radek Krejci84ce7b12020-06-11 17:28:25 +0200275 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100276}
277
278char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200279ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100280{
281 char *data;
282
Radek Krejci241f6b52020-05-21 18:13:49 +0200283 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100284
285 data = *out->method.mem.buf;
286
287 if (strp) {
288 out->method.mem.buf = strp;
289 out->method.mem.len = out->method.mem.size = 0;
290 out->printed = 0;
291 if (!size) {
292 /* buffer is supposed to be allocated */
293 *strp = NULL;
294 } else if (*strp) {
295 /* there is already buffer to use */
296 out->method.mem.size = size;
297 }
298 }
299
300 return data;
301}
302
303API LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200304ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100305{
306 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
307
Michal Vaskod989ba02020-08-24 10:59:24 +0200308 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200309 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100310 LOGINT(NULL);
311 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200312 case LY_OUT_FD:
Michal Vasko69730152020-10-09 16:30:07 +0200313 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100314 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
315 return LY_ESYS;
316 }
Michal Vasko69730152020-10-09 16:30:07 +0200317 if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200318 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
319 return LY_ESYS;
320 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100321 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200322 case LY_OUT_FDSTREAM:
323 case LY_OUT_FILE:
324 case LY_OUT_FILEPATH:
Michal Vasko69730152020-10-09 16:30:07 +0200325 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100326 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
327 return LY_ESYS;
328 }
Michal Vasko69730152020-10-09 16:30:07 +0200329 if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200330 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
331 return LY_ESYS;
332 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100333 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200334 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200335 if (out->method.mem.buf && *out->method.mem.buf) {
336 memset(*out->method.mem.buf, 0, out->method.mem.len);
337 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100338 out->printed = 0;
339 out->method.mem.len = 0;
340 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200341 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100342 /* nothing to do (not seekable) */
343 break;
344 }
345
346 return LY_SUCCESS;
347}
348
Radek Krejci84ce7b12020-06-11 17:28:25 +0200349API LY_ERR
350ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100351{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200352 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100353
Radek Krejci84ce7b12020-06-11 17:28:25 +0200354 *out = calloc(1, sizeof **out);
355 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100356
Radek Krejci84ce7b12020-06-11 17:28:25 +0200357 (*out)->type = LY_OUT_FILEPATH;
358 (*out)->method.fpath.f = fopen(filepath, "w");
359 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100360 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200361 free(*out);
362 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200363 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100364 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200365 (*out)->method.fpath.filepath = strdup(filepath);
366 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100367}
368
369API const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200370ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100371{
372 FILE *f;
373
Radek Krejci241f6b52020-05-21 18:13:49 +0200374 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100375
376 if (!filepath) {
377 return out->method.fpath.filepath;
378 }
379
380 /* replace filepath */
381 f = out->method.fpath.f;
382 out->method.fpath.f = fopen(filepath, "w");
383 if (!out->method.fpath.f) {
384 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
385 out->method.fpath.f = f;
Michal Vasko69730152020-10-09 16:30:07 +0200386 return (void *)-1;
Radek Krejcia5bba312020-01-09 15:41:20 +0100387 }
388 fclose(f);
389 free(out->method.fpath.filepath);
390 out->method.fpath.filepath = strdup(filepath);
391
392 return NULL;
393}
394
395API void
Radek Krejci857189e2020-09-01 13:26:36 +0200396ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100397{
398 if (!out) {
399 return;
400 }
401
402 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200403 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100404 if (clb_arg_destructor) {
405 clb_arg_destructor(out->method.clb.arg);
406 }
407 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200408 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100409 fclose(out->method.fdstream.f);
410 if (destroy) {
411 close(out->method.fdstream.fd);
412 }
413 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200414 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100415 if (destroy) {
416 close(out->method.fd);
417 }
418 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200419 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100420 if (destroy) {
421 fclose(out->method.f);
422 }
423 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200424 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100425 if (destroy) {
426 free(*out->method.mem.buf);
427 }
428 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200429 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100430 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200431 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100432 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200433 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100434 LOGINT(NULL);
435 }
Michal Vasko159b8872020-11-18 18:14:16 +0100436
437 free(out->buffered);
Radek Krejcia5bba312020-01-09 15:41:20 +0100438 free(out);
439}
440
Michal Vasko5233e962020-08-14 14:26:20 +0200441static LY_ERR
442ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200443{
Michal Vasko5233e962020-08-14 14:26:20 +0200444 LY_ERR ret;
445 int written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200446 char *msg = NULL, *aux;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200447
448 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200449 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200450 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200451 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200452 case LY_OUT_FDSTREAM:
453 case LY_OUT_FILEPATH:
454 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200455 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200456 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200457 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200458 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200459 break;
460 }
Michal Vasko5233e962020-08-14 14:26:20 +0200461 if (out->method.mem.len + written + 1 > out->method.mem.size) {
462 aux = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200463 if (!aux) {
464 out->method.mem.buf = NULL;
465 out->method.mem.len = 0;
466 out->method.mem.size = 0;
467 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200468 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200469 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100470 *out->method.mem.buf = aux;
Michal Vasko5233e962020-08-14 14:26:20 +0200471 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200472 }
Michal Vasko5233e962020-08-14 14:26:20 +0200473 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
474 out->method.mem.len += written;
Radek Krejcia5bba312020-01-09 15:41:20 +0100475 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejcid3ca0632019-04-16 16:54:54 +0200476 free(msg);
477 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200478 case LY_OUT_CALLBACK:
Michal Vasko5233e962020-08-14 14:26:20 +0200479 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200480 break;
481 }
Michal Vasko5233e962020-08-14 14:26:20 +0200482 written = out->method.clb.func(out->method.clb.arg, msg, written);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200483 free(msg);
484 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200485 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100486 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200487 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200488 }
489
Michal Vasko5233e962020-08-14 14:26:20 +0200490 if (written < 0) {
491 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
492 written = 0;
493 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200494 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200495 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100496 /* move the original file descriptor to the end of the output file */
497 lseek(out->method.fdstream.fd, 0, SEEK_END);
498 }
Michal Vasko5233e962020-08-14 14:26:20 +0200499 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200500 }
Michal Vasko5233e962020-08-14 14:26:20 +0200501
502 out->printed += written;
503 out->func_printed += written;
504 return ret;
505}
506
507LY_ERR
508ly_print_(struct ly_out *out, const char *format, ...)
509{
510 LY_ERR ret;
511 va_list ap;
512
513 va_start(ap, format);
514 ret = ly_vprint_(out, format, ap);
515 va_end(ap);
516
517 return ret;
518}
519
520API LY_ERR
521ly_print(struct ly_out *out, const char *format, ...)
522{
523 LY_ERR ret;
524 va_list ap;
525
526 out->func_printed = 0;
527
528 va_start(ap, format);
529 ret = ly_vprint_(out, format, ap);
530 va_end(ap);
531
532 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200533}
534
Radek Krejci2aae3752020-05-27 18:16:30 +0200535API void
Radek Krejci241f6b52020-05-21 18:13:49 +0200536ly_print_flush(struct ly_out *out)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200537{
538 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200539 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100540 /* move the original file descriptor to the end of the output file */
541 lseek(out->method.fdstream.fd, 0, SEEK_END);
542 fflush(out->method.fdstream.f);
543 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200544 case LY_OUT_FILEPATH:
545 case LY_OUT_FILE:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200546 fflush(out->method.f);
547 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200548 case LY_OUT_FD:
Radek Krejcie7b95092019-05-15 11:03:07 +0200549 fsync(out->method.fd);
550 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200551 case LY_OUT_MEMORY:
552 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200553 /* nothing to do */
554 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200555 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100556 LOGINT(NULL);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200557 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200558
559 free(out->buffered);
560 out->buf_size = out->buf_len = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200561}
562
Michal Vasko5233e962020-08-14 14:26:20 +0200563LY_ERR
564ly_write_(struct ly_out *out, const char *buf, size_t len)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200565{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200566 LY_ERR ret = LY_SUCCESS;
567 size_t written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200568
569 if (out->hole_count) {
570 /* we are buffering data after a hole */
Radek Krejcie7b95092019-05-15 11:03:07 +0200571 if (out->buf_len + len > out->buf_size) {
572 out->buffered = ly_realloc(out->buffered, out->buf_len + len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200573 if (!out->buffered) {
574 out->buf_len = 0;
575 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200576 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200577 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200578 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200579 out->buf_size = out->buf_len + len;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200580 }
581
Radek Krejcie7b95092019-05-15 11:03:07 +0200582 memcpy(&out->buffered[out->buf_len], buf, len);
583 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200584
585 out->printed += len;
586 out->func_printed += len;
587 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200588 }
589
Radek Krejci897ad2e2019-04-29 16:43:07 +0200590repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200591 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200592 case LY_OUT_MEMORY:
Radek Krejcie7b95092019-05-15 11:03:07 +0200593 if (out->method.mem.len + len + 1 > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100594 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + len + 1);
595 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200596 out->method.mem.len = 0;
597 out->method.mem.size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200598 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200599 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200600 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200601 out->method.mem.size = out->method.mem.len + len + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200602 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100603 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200604 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100605 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200606
Michal Vasko5233e962020-08-14 14:26:20 +0200607 written = len;
608 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200609 case LY_OUT_FD: {
610 ssize_t r;
611 r = write(out->method.fd, buf, len);
612 if (r < 0) {
613 ret = LY_ESYS;
614 } else {
615 written = (size_t)r;
616 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200617 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200618 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200619 case LY_OUT_FDSTREAM:
620 case LY_OUT_FILEPATH:
621 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200622 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200623 if (written != len) {
624 ret = LY_ESYS;
625 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200626 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200627 case LY_OUT_CALLBACK: {
628 ssize_t r;
629 r = out->method.clb.func(out->method.clb.arg, buf, len);
630 if (r < 0) {
631 ret = LY_ESYS;
632 } else {
633 written = (size_t)r;
634 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200635 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200636 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200637 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100638 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200639 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200640 }
641
Radek Krejci1deb5be2020-08-26 16:43:36 +0200642 if (ret) {
Michal Vasko69730152020-10-09 16:30:07 +0200643 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200644 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200645 goto repeat;
646 }
Michal Vasko5233e962020-08-14 14:26:20 +0200647 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
648 written = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200649 } else if ((size_t)written != len) {
Michal Vasko5233e962020-08-14 14:26:20 +0200650 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__,
Michal Vasko69730152020-10-09 16:30:07 +0200651 len - (size_t)written, len);
Michal Vasko5233e962020-08-14 14:26:20 +0200652 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200653 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200654 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100655 /* move the original file descriptor to the end of the output file */
656 lseek(out->method.fdstream.fd, 0, SEEK_END);
657 }
Michal Vasko5233e962020-08-14 14:26:20 +0200658 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200659 }
Michal Vasko5233e962020-08-14 14:26:20 +0200660
661 out->printed += written;
662 out->func_printed += written;
663 return ret;
664}
665
666API LY_ERR
667ly_write(struct ly_out *out, const char *buf, size_t len)
668{
669 out->func_printed = 0;
670
671 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200672}
673
Michal Vasko63f3d842020-07-08 10:10:14 +0200674API size_t
675ly_out_printed(const struct ly_out *out)
676{
677 return out->func_printed;
678}
679
Michal Vasko5233e962020-08-14 14:26:20 +0200680LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200681ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200682{
683 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200684 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200685 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100686 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
687 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200688 out->method.mem.len = 0;
689 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200690 LOGMEM(NULL);
691 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200692 }
693 out->method.mem.size = out->method.mem.len + count;
694 }
695
696 /* save the current position */
697 *position = out->method.mem.len;
698
699 /* skip the memory */
700 out->method.mem.len += count;
701 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200702 case LY_OUT_FD:
703 case LY_OUT_FDSTREAM:
704 case LY_OUT_FILEPATH:
705 case LY_OUT_FILE:
706 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200707 /* buffer the hole */
708 if (out->buf_len + count > out->buf_size) {
709 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
710 if (!out->buffered) {
711 out->buf_len = 0;
712 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200713 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200714 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200715 }
716 out->buf_size = out->buf_len + count;
717 }
718
719 /* save the current position */
720 *position = out->buf_len;
721
722 /* skip the memory */
723 out->buf_len += count;
724
725 /* increase hole counter */
726 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100727 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200728 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100729 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200730 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200731 }
732
Michal Vasko5233e962020-08-14 14:26:20 +0200733 /* update printed bytes counter despite we actually printed just a hole */
734 out->printed += count;
735 out->func_printed += count;
736 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200737}
738
Michal Vasko66d99972020-06-29 13:37:42 +0200739LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200740ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200741{
Michal Vasko66d99972020-06-29 13:37:42 +0200742 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200743
744 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200745 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200746 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100747 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200748 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200749 case LY_OUT_FD:
750 case LY_OUT_FDSTREAM:
751 case LY_OUT_FILEPATH:
752 case LY_OUT_FILE:
753 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200754 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200755 LOGMEM(NULL);
756 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200757 }
758
759 /* write into the hole */
760 memcpy(&out->buffered[position], buf, count);
761
762 /* decrease hole counter */
763 --out->hole_count;
764
765 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200766 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200767 * printed bytes counter is updated by ly_write_() */
768 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200769 out->buf_len = 0;
770 }
771 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200772 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200773 LOGINT(NULL);
774 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200775 }
776
Radek Krejci241f6b52020-05-21 18:13:49 +0200777 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100778 /* move the original file descriptor to the end of the output file */
779 lseek(out->method.fdstream.fd, 0, SEEK_END);
780 }
Michal Vasko66d99972020-06-29 13:37:42 +0200781 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200782}