blob: b74ed64f2b5d6b5ab7a9a72124b4b03ecae7a9fe [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 Vasko56daf732020-08-10 10:57:18 +020079 const struct lyd_node *elem;
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 }
Radek Krejci7931b192020-06-25 17:05:03 +020092 } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
Radek Krejci241f6b52020-05-21 18:13:49 +020093 /* LYDP_WD_EXPLICIT
Michal Vasko9b368d32020-02-14 13:53:31 +010094 * - print only if it contains status data in its subtree */
Michal Vasko56daf732020-08-10 10:57:18 +020095 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vaskodb4f9e42020-06-01 17:29:56 +020096 if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
97 if (elem->schema->flags & LYS_CONFIG_R) {
98 return 1;
99 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100100 }
Michal Vasko56daf732020-08-10 10:57:18 +0200101 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100102 }
103 return 0;
Radek Krejci7931b192020-06-25 17:05:03 +0200104 } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYD_PRINT_KEEPEMPTYCONT)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100105 /* avoid empty default containers */
Michal Vasko56daf732020-08-10 10:57:18 +0200106 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100107 if (elem->schema->nodetype != LYS_CONTAINER) {
108 return 1;
109 }
110 assert(elem->flags & LYD_DEFAULT);
Michal Vasko56daf732020-08-10 10:57:18 +0200111 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100112 }
113 return 0;
114 }
115
116 return 1;
117}
118
Radek Krejci241f6b52020-05-21 18:13:49 +0200119API LY_OUT_TYPE
120ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100121{
Radek Krejci241f6b52020-05-21 18:13:49 +0200122 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100123 return out->type;
124}
125
Radek Krejci84ce7b12020-06-11 17:28:25 +0200126API LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200127ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100128{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200129 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100130
Radek Krejci84ce7b12020-06-11 17:28:25 +0200131 *out = calloc(1, sizeof **out);
132 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100133
Radek Krejci84ce7b12020-06-11 17:28:25 +0200134 (*out)->type = LY_OUT_CALLBACK;
135 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200136 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100137
Radek Krejci84ce7b12020-06-11 17:28:25 +0200138 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100139}
140
Michal Vasko69730152020-10-09 16:30:07 +0200141API ly_write_clb
142ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100143{
144 void *prev_clb;
145
Radek Krejci241f6b52020-05-21 18:13:49 +0200146 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100147
148 prev_clb = out->method.clb.func;
149
150 if (writeclb) {
151 out->method.clb.func = writeclb;
152 }
153
154 return prev_clb;
155}
156
157API void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200158ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100159{
160 void *prev_arg;
161
Radek Krejci241f6b52020-05-21 18:13:49 +0200162 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100163
164 prev_arg = out->method.clb.arg;
165
166 if (arg) {
167 out->method.clb.arg = arg;
168 }
169
170 return prev_arg;
171}
172
Radek Krejci84ce7b12020-06-11 17:28:25 +0200173API LY_ERR
174ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100175{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200176 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100177
Radek Krejci84ce7b12020-06-11 17:28:25 +0200178 *out = calloc(1, sizeof **out);
179 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200180 (*out)->type = LY_OUT_FD;
181 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100182
Radek Krejci84ce7b12020-06-11 17:28:25 +0200183 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100184}
185
186API int
Radek Krejci241f6b52020-05-21 18:13:49 +0200187ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100188{
189 int prev_fd;
190
Radek Krejci241f6b52020-05-21 18:13:49 +0200191 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100192
Radek Krejci241f6b52020-05-21 18:13:49 +0200193 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100194 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200195 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100196 prev_fd = out->method.fd;
197 }
198
199 if (fd != -1) {
200 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200201 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100202 int streamfd;
203 FILE *stream;
204
205 streamfd = dup(fd);
206 if (streamfd < 0) {
207 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
208 return -1;
209 }
210 stream = fdopen(streamfd, "a");
211 if (!stream) {
212 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
213 close(streamfd);
214 return -1;
215 }
216 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
217 fclose(out->method.fdstream.f);
218 out->method.fdstream.f = stream;
219 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200220 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100221 out->method.fd = fd;
222 }
223 }
224
225 return prev_fd;
226}
227
Radek Krejci84ce7b12020-06-11 17:28:25 +0200228API LY_ERR
229ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100230{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200231 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100232
Radek Krejci84ce7b12020-06-11 17:28:25 +0200233 *out = calloc(1, sizeof **out);
234 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100235
Radek Krejci84ce7b12020-06-11 17:28:25 +0200236 (*out)->type = LY_OUT_FILE;
237 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100238
Radek Krejci84ce7b12020-06-11 17:28:25 +0200239 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100240}
241
242API FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200243ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100244{
245 FILE *prev_f;
246
Radek Krejci241f6b52020-05-21 18:13:49 +0200247 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100248
249 prev_f = out->method.f;
250
251 if (f) {
252 out->method.f = f;
253 }
254
255 return prev_f;
256}
257
Radek Krejci84ce7b12020-06-11 17:28:25 +0200258API LY_ERR
259ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100260{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200261 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100262
Radek Krejci84ce7b12020-06-11 17:28:25 +0200263 *out = calloc(1, sizeof **out);
264 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100265
Radek Krejci84ce7b12020-06-11 17:28:25 +0200266 (*out)->type = LY_OUT_MEMORY;
267 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100268 if (!size) {
269 /* buffer is supposed to be allocated */
270 *strp = NULL;
271 } else if (*strp) {
272 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200273 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100274 }
275
Radek Krejci84ce7b12020-06-11 17:28:25 +0200276 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100277}
278
279char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200280ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100281{
282 char *data;
283
Radek Krejci241f6b52020-05-21 18:13:49 +0200284 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100285
286 data = *out->method.mem.buf;
287
288 if (strp) {
289 out->method.mem.buf = strp;
290 out->method.mem.len = out->method.mem.size = 0;
291 out->printed = 0;
292 if (!size) {
293 /* buffer is supposed to be allocated */
294 *strp = NULL;
295 } else if (*strp) {
296 /* there is already buffer to use */
297 out->method.mem.size = size;
298 }
299 }
300
301 return data;
302}
303
304API LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200305ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100306{
307 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
308
Michal Vaskod989ba02020-08-24 10:59:24 +0200309 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200310 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100311 LOGINT(NULL);
312 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200313 case LY_OUT_FD:
Michal Vasko69730152020-10-09 16:30:07 +0200314 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100315 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
316 return LY_ESYS;
317 }
Michal Vasko69730152020-10-09 16:30:07 +0200318 if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200319 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
320 return LY_ESYS;
321 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100322 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200323 case LY_OUT_FDSTREAM:
324 case LY_OUT_FILE:
325 case LY_OUT_FILEPATH:
Michal Vasko69730152020-10-09 16:30:07 +0200326 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100327 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
328 return LY_ESYS;
329 }
Michal Vasko69730152020-10-09 16:30:07 +0200330 if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200331 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
332 return LY_ESYS;
333 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100334 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200335 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200336 if (out->method.mem.buf && *out->method.mem.buf) {
337 memset(*out->method.mem.buf, 0, out->method.mem.len);
338 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100339 out->printed = 0;
340 out->method.mem.len = 0;
341 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200342 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100343 /* nothing to do (not seekable) */
344 break;
345 }
346
347 return LY_SUCCESS;
348}
349
Radek Krejci84ce7b12020-06-11 17:28:25 +0200350API LY_ERR
351ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100352{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200353 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100354
Radek Krejci84ce7b12020-06-11 17:28:25 +0200355 *out = calloc(1, sizeof **out);
356 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100357
Radek Krejci84ce7b12020-06-11 17:28:25 +0200358 (*out)->type = LY_OUT_FILEPATH;
359 (*out)->method.fpath.f = fopen(filepath, "w");
360 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100361 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200362 free(*out);
363 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200364 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100365 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200366 (*out)->method.fpath.filepath = strdup(filepath);
367 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100368}
369
370API const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200371ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100372{
373 FILE *f;
374
Radek Krejci241f6b52020-05-21 18:13:49 +0200375 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100376
377 if (!filepath) {
378 return out->method.fpath.filepath;
379 }
380
381 /* replace filepath */
382 f = out->method.fpath.f;
383 out->method.fpath.f = fopen(filepath, "w");
384 if (!out->method.fpath.f) {
385 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
386 out->method.fpath.f = f;
Michal Vasko69730152020-10-09 16:30:07 +0200387 return (void *)-1;
Radek Krejcia5bba312020-01-09 15:41:20 +0100388 }
389 fclose(f);
390 free(out->method.fpath.filepath);
391 out->method.fpath.filepath = strdup(filepath);
392
393 return NULL;
394}
395
396API void
Radek Krejci857189e2020-09-01 13:26:36 +0200397ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100398{
399 if (!out) {
400 return;
401 }
402
403 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200404 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100405 if (clb_arg_destructor) {
406 clb_arg_destructor(out->method.clb.arg);
407 }
408 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200409 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100410 fclose(out->method.fdstream.f);
411 if (destroy) {
412 close(out->method.fdstream.fd);
413 }
414 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200415 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100416 if (destroy) {
417 close(out->method.fd);
418 }
419 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200420 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100421 if (destroy) {
422 fclose(out->method.f);
423 }
424 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200425 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100426 if (destroy) {
427 free(*out->method.mem.buf);
428 }
429 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200430 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100431 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200432 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100433 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200434 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100435 LOGINT(NULL);
436 }
Michal Vasko159b8872020-11-18 18:14:16 +0100437
438 free(out->buffered);
Radek Krejcia5bba312020-01-09 15:41:20 +0100439 free(out);
440}
441
Michal Vasko5233e962020-08-14 14:26:20 +0200442static LY_ERR
443ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200444{
Michal Vasko5233e962020-08-14 14:26:20 +0200445 LY_ERR ret;
446 int written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200447 char *msg = NULL, *aux;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200448
449 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200450 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200451 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200452 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200453 case LY_OUT_FDSTREAM:
454 case LY_OUT_FILEPATH:
455 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200456 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200457 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200458 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200459 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200460 break;
461 }
Michal Vasko5233e962020-08-14 14:26:20 +0200462 if (out->method.mem.len + written + 1 > out->method.mem.size) {
463 aux = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200464 if (!aux) {
465 out->method.mem.buf = NULL;
466 out->method.mem.len = 0;
467 out->method.mem.size = 0;
468 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200469 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200470 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100471 *out->method.mem.buf = aux;
Michal Vasko5233e962020-08-14 14:26:20 +0200472 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200473 }
Michal Vasko5233e962020-08-14 14:26:20 +0200474 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
475 out->method.mem.len += written;
Radek Krejcia5bba312020-01-09 15:41:20 +0100476 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejcid3ca0632019-04-16 16:54:54 +0200477 free(msg);
478 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200479 case LY_OUT_CALLBACK:
Michal Vasko5233e962020-08-14 14:26:20 +0200480 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200481 break;
482 }
Michal Vasko5233e962020-08-14 14:26:20 +0200483 written = out->method.clb.func(out->method.clb.arg, msg, written);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200484 free(msg);
485 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200486 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100487 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200488 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200489 }
490
Michal Vasko5233e962020-08-14 14:26:20 +0200491 if (written < 0) {
492 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
493 written = 0;
494 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200495 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200496 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100497 /* move the original file descriptor to the end of the output file */
498 lseek(out->method.fdstream.fd, 0, SEEK_END);
499 }
Michal Vasko5233e962020-08-14 14:26:20 +0200500 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200501 }
Michal Vasko5233e962020-08-14 14:26:20 +0200502
503 out->printed += written;
504 out->func_printed += written;
505 return ret;
506}
507
508LY_ERR
509ly_print_(struct ly_out *out, const char *format, ...)
510{
511 LY_ERR ret;
512 va_list ap;
513
514 va_start(ap, format);
515 ret = ly_vprint_(out, format, ap);
516 va_end(ap);
517
518 return ret;
519}
520
521API LY_ERR
522ly_print(struct ly_out *out, const char *format, ...)
523{
524 LY_ERR ret;
525 va_list ap;
526
527 out->func_printed = 0;
528
529 va_start(ap, format);
530 ret = ly_vprint_(out, format, ap);
531 va_end(ap);
532
533 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200534}
535
Radek Krejci2aae3752020-05-27 18:16:30 +0200536API void
Radek Krejci241f6b52020-05-21 18:13:49 +0200537ly_print_flush(struct ly_out *out)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200538{
539 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200540 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100541 /* move the original file descriptor to the end of the output file */
542 lseek(out->method.fdstream.fd, 0, SEEK_END);
543 fflush(out->method.fdstream.f);
544 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200545 case LY_OUT_FILEPATH:
546 case LY_OUT_FILE:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200547 fflush(out->method.f);
548 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200549 case LY_OUT_FD:
Radek Krejcie7b95092019-05-15 11:03:07 +0200550 fsync(out->method.fd);
551 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200552 case LY_OUT_MEMORY:
553 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200554 /* nothing to do */
555 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200556 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100557 LOGINT(NULL);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200558 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200559
560 free(out->buffered);
561 out->buf_size = out->buf_len = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200562}
563
Michal Vasko5233e962020-08-14 14:26:20 +0200564LY_ERR
565ly_write_(struct ly_out *out, const char *buf, size_t len)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200566{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200567 LY_ERR ret = LY_SUCCESS;
568 size_t written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200569
570 if (out->hole_count) {
571 /* we are buffering data after a hole */
Radek Krejcie7b95092019-05-15 11:03:07 +0200572 if (out->buf_len + len > out->buf_size) {
573 out->buffered = ly_realloc(out->buffered, out->buf_len + len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200574 if (!out->buffered) {
575 out->buf_len = 0;
576 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200577 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200578 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200579 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200580 out->buf_size = out->buf_len + len;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200581 }
582
Radek Krejcie7b95092019-05-15 11:03:07 +0200583 memcpy(&out->buffered[out->buf_len], buf, len);
584 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200585
586 out->printed += len;
587 out->func_printed += len;
588 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200589 }
590
Radek Krejci897ad2e2019-04-29 16:43:07 +0200591repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200592 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200593 case LY_OUT_MEMORY:
Radek Krejcie7b95092019-05-15 11:03:07 +0200594 if (out->method.mem.len + len + 1 > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100595 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + len + 1);
596 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200597 out->method.mem.len = 0;
598 out->method.mem.size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200599 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200600 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200601 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200602 out->method.mem.size = out->method.mem.len + len + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200603 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100604 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200605 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100606 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200607
Michal Vasko5233e962020-08-14 14:26:20 +0200608 written = len;
609 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200610 case LY_OUT_FD: {
611 ssize_t r;
612 r = write(out->method.fd, buf, len);
613 if (r < 0) {
614 ret = LY_ESYS;
615 } else {
616 written = (size_t)r;
617 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200618 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200619 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200620 case LY_OUT_FDSTREAM:
621 case LY_OUT_FILEPATH:
622 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200623 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200624 if (written != len) {
625 ret = LY_ESYS;
626 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200627 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200628 case LY_OUT_CALLBACK: {
629 ssize_t r;
630 r = out->method.clb.func(out->method.clb.arg, buf, len);
631 if (r < 0) {
632 ret = LY_ESYS;
633 } else {
634 written = (size_t)r;
635 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200636 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200637 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200638 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100639 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200640 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200641 }
642
Radek Krejci1deb5be2020-08-26 16:43:36 +0200643 if (ret) {
Michal Vasko69730152020-10-09 16:30:07 +0200644 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200645 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200646 goto repeat;
647 }
Michal Vasko5233e962020-08-14 14:26:20 +0200648 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
649 written = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200650 } else if ((size_t)written != len) {
Michal Vasko5233e962020-08-14 14:26:20 +0200651 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__,
Michal Vasko69730152020-10-09 16:30:07 +0200652 len - (size_t)written, len);
Michal Vasko5233e962020-08-14 14:26:20 +0200653 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200654 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200655 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100656 /* move the original file descriptor to the end of the output file */
657 lseek(out->method.fdstream.fd, 0, SEEK_END);
658 }
Michal Vasko5233e962020-08-14 14:26:20 +0200659 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200660 }
Michal Vasko5233e962020-08-14 14:26:20 +0200661
662 out->printed += written;
663 out->func_printed += written;
664 return ret;
665}
666
667API LY_ERR
668ly_write(struct ly_out *out, const char *buf, size_t len)
669{
670 out->func_printed = 0;
671
672 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200673}
674
Michal Vasko63f3d842020-07-08 10:10:14 +0200675API size_t
676ly_out_printed(const struct ly_out *out)
677{
678 return out->func_printed;
679}
680
Michal Vasko5233e962020-08-14 14:26:20 +0200681LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200682ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200683{
684 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200685 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200686 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100687 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
688 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200689 out->method.mem.len = 0;
690 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200691 LOGMEM(NULL);
692 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200693 }
694 out->method.mem.size = out->method.mem.len + count;
695 }
696
697 /* save the current position */
698 *position = out->method.mem.len;
699
700 /* skip the memory */
701 out->method.mem.len += count;
702 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200703 case LY_OUT_FD:
704 case LY_OUT_FDSTREAM:
705 case LY_OUT_FILEPATH:
706 case LY_OUT_FILE:
707 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200708 /* buffer the hole */
709 if (out->buf_len + count > out->buf_size) {
710 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
711 if (!out->buffered) {
712 out->buf_len = 0;
713 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200714 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200715 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200716 }
717 out->buf_size = out->buf_len + count;
718 }
719
720 /* save the current position */
721 *position = out->buf_len;
722
723 /* skip the memory */
724 out->buf_len += count;
725
726 /* increase hole counter */
727 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100728 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200729 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100730 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200731 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200732 }
733
Michal Vasko5233e962020-08-14 14:26:20 +0200734 /* update printed bytes counter despite we actually printed just a hole */
735 out->printed += count;
736 out->func_printed += count;
737 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200738}
739
Michal Vasko66d99972020-06-29 13:37:42 +0200740LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200741ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200742{
Michal Vasko66d99972020-06-29 13:37:42 +0200743 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200744
745 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200746 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200747 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100748 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200749 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200750 case LY_OUT_FD:
751 case LY_OUT_FDSTREAM:
752 case LY_OUT_FILEPATH:
753 case LY_OUT_FILE:
754 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200755 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200756 LOGMEM(NULL);
757 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200758 }
759
760 /* write into the hole */
761 memcpy(&out->buffered[position], buf, count);
762
763 /* decrease hole counter */
764 --out->hole_count;
765
766 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200767 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200768 * printed bytes counter is updated by ly_write_() */
769 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200770 out->buf_len = 0;
771 }
772 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200773 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200774 LOGINT(NULL);
775 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200776 }
777
Radek Krejci241f6b52020-05-21 18:13:49 +0200778 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100779 /* move the original file descriptor to the end of the output file */
780 lseek(out->method.fdstream.fd, 0, SEEK_END);
781 }
Michal Vasko66d99972020-06-29 13:37:42 +0200782 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200783}