blob: 081abf588da1bd70a9fc7b3596f821a8096eb7d5 [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
Christian Hopps32874e12021-05-01 09:43:54 -040015#define _GNU_SOURCE /* asprintf, strdup */
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
Michal Vasko5aa44c02020-06-29 11:47:02 +020029#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010031#include "ly_common.h"
aPiecek6cf1d162023-11-08 16:07:00 +010032#include "metadata.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020033#include "printer_data.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
aPiecek61d76952021-08-30 10:28:04 +020037/**
38 * @brief Align the desired size to 1 KB.
39 */
40#define REALLOC_CHUNK(NEW_SIZE) \
41 NEW_SIZE + (1024 - (NEW_SIZE % 1024))
42
Michal Vasko8db584d2022-03-30 13:42:48 +020043LIBYANG_API_DEF ly_bool
44lyd_node_should_print(const struct lyd_node *node, uint32_t options)
Michal Vasko9b368d32020-02-14 13:53:31 +010045{
Michal Vaskob4fd37f2021-02-26 10:09:44 +010046 const struct lyd_node *elem;
Michal Vasko9b368d32020-02-14 13:53:31 +010047
Radek Krejci7931b192020-06-25 17:05:03 +020048 if (options & LYD_PRINT_WD_TRIM) {
Michal Vasko9b368d32020-02-14 13:53:31 +010049 /* do not print default nodes */
50 if (node->flags & LYD_DEFAULT) {
51 /* implicit default node/NP container with only default nodes */
52 return 0;
Michal Vaskobd777662021-07-09 13:58:40 +020053 } else if (node->schema && (node->schema->nodetype & LYD_NODE_TERM)) {
Radek Krejci19611252020-10-04 13:54:53 +020054 if (lyd_is_default(node)) {
Michal Vasko9b368d32020-02-14 13:53:31 +010055 /* explicit default node */
56 return 0;
57 }
Michal Vaskoee3539a2024-04-25 08:40:56 +020058 } else if (lysc_is_np_cont(node->schema)) {
59 if (options & LYD_PRINT_KEEPEMPTYCONT) {
60 /* explicit request to print, redundant to check */
61 return 1;
62 }
63
64 LY_LIST_FOR(lyd_child(node), elem) {
65 if (lyd_node_should_print(elem, options)) {
66 return 1;
67 }
68 }
69
70 /* NP container without any printed children (such as other NP containers with only nodes set to their default values) */
71 return 0;
Michal Vasko9b368d32020-02-14 13:53:31 +010072 }
Michal Vasko1dd384e2021-07-08 13:59:55 +020073 } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER)) {
74 if (options & LYD_PRINT_KEEPEMPTYCONT) {
75 /* explicit request to print */
76 return 1;
77 }
78
79 /* avoid empty default containers */
80 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vasko8db584d2022-03-30 13:42:48 +020081 if ((elem != node) && lyd_node_should_print(elem, options)) {
Michal Vasko1dd384e2021-07-08 13:59:55 +020082 return 1;
83 }
84 assert(elem->flags & LYD_DEFAULT);
85 LYD_TREE_DFS_END(node, elem)
86 }
87 return 0;
Michal Vasko0d5ea7e2021-02-26 10:10:15 +010088 } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko5be03d62020-12-09 18:08:39 +010089 /* LYD_PRINT_WD_EXPLICIT, find out if this is some input/output */
Michal Vaskob4fd37f2021-02-26 10:09:44 +010090 if (!(node->schema->flags & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) && (node->schema->flags & LYS_CONFIG_W)) {
Michal Vasko5be03d62020-12-09 18:08:39 +010091 /* print only if it contains status data in its subtree */
92 LYD_TREE_DFS_BEGIN(node, elem) {
93 if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
94 if (elem->schema->flags & LYS_CONFIG_R) {
95 return 1;
96 }
Michal Vaskodb4f9e42020-06-01 17:29:56 +020097 }
Michal Vasko5be03d62020-12-09 18:08:39 +010098 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +010099 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100100 }
101 return 0;
Michal Vasko9b368d32020-02-14 13:53:31 +0100102 }
103
104 return 1;
105}
106
aPiecek6cf1d162023-11-08 16:07:00 +0100107LIBYANG_API_DEF ly_bool
108lyd_metadata_should_print(const struct lyd_meta *meta)
109{
110 const char *arg;
111
112 assert(meta->annotation);
113
114 arg = meta->annotation->argument;
115 if (!strcmp(arg, "lyds_tree")) {
116 return 0;
117 } else {
118 return 1;
119 }
120}
121
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100122LIBYANG_API_DEF LY_OUT_TYPE
Radek Krejci241f6b52020-05-21 18:13:49 +0200123ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100124{
Radek Krejci241f6b52020-05-21 18:13:49 +0200125 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100126 return out->type;
127}
128
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100129LIBYANG_API_DEF LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200130ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100131{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200132 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100133
Radek Krejci84ce7b12020-06-11 17:28:25 +0200134 *out = calloc(1, sizeof **out);
135 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100136
Radek Krejci84ce7b12020-06-11 17:28:25 +0200137 (*out)->type = LY_OUT_CALLBACK;
138 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200139 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100140
Radek Krejci84ce7b12020-06-11 17:28:25 +0200141 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100142}
143
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100144LIBYANG_API_DEF ly_write_clb
Michal Vasko69730152020-10-09 16:30:07 +0200145ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100146{
Michal Vasko59e90fc2021-09-22 12:17:08 +0200147 ly_write_clb prev_clb;
Radek Krejcia5bba312020-01-09 15:41:20 +0100148
Radek Krejci241f6b52020-05-21 18:13:49 +0200149 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100150
151 prev_clb = out->method.clb.func;
152
153 if (writeclb) {
154 out->method.clb.func = writeclb;
155 }
156
157 return prev_clb;
158}
159
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100160LIBYANG_API_DEF void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200161ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100162{
163 void *prev_arg;
164
Radek Krejci241f6b52020-05-21 18:13:49 +0200165 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100166
167 prev_arg = out->method.clb.arg;
168
169 if (arg) {
170 out->method.clb.arg = arg;
171 }
172
173 return prev_arg;
174}
175
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100176LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200177ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100178{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200179 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100180
Radek Krejci84ce7b12020-06-11 17:28:25 +0200181 *out = calloc(1, sizeof **out);
182 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200183 (*out)->type = LY_OUT_FD;
184 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100185
Radek Krejci84ce7b12020-06-11 17:28:25 +0200186 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100187}
188
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100189LIBYANG_API_DEF int
Radek Krejci241f6b52020-05-21 18:13:49 +0200190ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100191{
192 int prev_fd;
193
Radek Krejci241f6b52020-05-21 18:13:49 +0200194 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100195
Radek Krejci241f6b52020-05-21 18:13:49 +0200196 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100197 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200198 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100199 prev_fd = out->method.fd;
200 }
201
202 if (fd != -1) {
203 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200204 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100205 int streamfd;
206 FILE *stream;
207
208 streamfd = dup(fd);
209 if (streamfd < 0) {
210 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
211 return -1;
212 }
213 stream = fdopen(streamfd, "a");
214 if (!stream) {
215 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
216 close(streamfd);
217 return -1;
218 }
219 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
220 fclose(out->method.fdstream.f);
221 out->method.fdstream.f = stream;
222 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200223 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100224 out->method.fd = fd;
225 }
226 }
227
228 return prev_fd;
229}
230
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100231LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200232ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100233{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200234 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100235
Radek Krejci84ce7b12020-06-11 17:28:25 +0200236 *out = calloc(1, sizeof **out);
237 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100238
Radek Krejci84ce7b12020-06-11 17:28:25 +0200239 (*out)->type = LY_OUT_FILE;
240 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100241
Radek Krejci84ce7b12020-06-11 17:28:25 +0200242 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100243}
244
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100245LIBYANG_API_DEF FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200246ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100247{
248 FILE *prev_f;
249
Radek Krejci241f6b52020-05-21 18:13:49 +0200250 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100251
252 prev_f = out->method.f;
253
254 if (f) {
255 out->method.f = f;
256 }
257
258 return prev_f;
259}
260
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100261LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200262ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100263{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200264 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100265
Radek Krejci84ce7b12020-06-11 17:28:25 +0200266 *out = calloc(1, sizeof **out);
267 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100268
Radek Krejci84ce7b12020-06-11 17:28:25 +0200269 (*out)->type = LY_OUT_MEMORY;
270 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100271 if (!size) {
272 /* buffer is supposed to be allocated */
273 *strp = NULL;
274 } else if (*strp) {
275 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200276 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100277 }
278
Radek Krejci84ce7b12020-06-11 17:28:25 +0200279 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100280}
281
282char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200283ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100284{
285 char *data;
286
Radek Krejci241f6b52020-05-21 18:13:49 +0200287 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100288
289 data = *out->method.mem.buf;
290
291 if (strp) {
292 out->method.mem.buf = strp;
293 out->method.mem.len = out->method.mem.size = 0;
294 out->printed = 0;
295 if (!size) {
296 /* buffer is supposed to be allocated */
297 *strp = NULL;
298 } else if (*strp) {
299 /* there is already buffer to use */
300 out->method.mem.size = size;
301 }
302 }
303
304 return data;
305}
306
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100307LIBYANG_API_DEF LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200308ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100309{
310 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
311
Michal Vaskod989ba02020-08-24 10:59:24 +0200312 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200313 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100314 LOGINT(NULL);
315 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200316 case LY_OUT_FD:
Michal Vasko69730152020-10-09 16:30:07 +0200317 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100318 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
319 return LY_ESYS;
320 }
Michal Vasko69730152020-10-09 16:30:07 +0200321 if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200322 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
323 return LY_ESYS;
324 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100325 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200326 case LY_OUT_FDSTREAM:
327 case LY_OUT_FILE:
328 case LY_OUT_FILEPATH:
Michal Vasko69730152020-10-09 16:30:07 +0200329 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100330 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
331 return LY_ESYS;
332 }
Michal Vasko69730152020-10-09 16:30:07 +0200333 if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200334 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
335 return LY_ESYS;
336 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100337 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200338 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200339 if (out->method.mem.buf && *out->method.mem.buf) {
340 memset(*out->method.mem.buf, 0, out->method.mem.len);
341 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100342 out->printed = 0;
343 out->method.mem.len = 0;
344 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200345 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100346 /* nothing to do (not seekable) */
347 break;
348 }
349
350 return LY_SUCCESS;
351}
352
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100353LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200354ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100355{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200356 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100357
Radek Krejci84ce7b12020-06-11 17:28:25 +0200358 *out = calloc(1, sizeof **out);
359 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100360
Radek Krejci84ce7b12020-06-11 17:28:25 +0200361 (*out)->type = LY_OUT_FILEPATH;
Jan Kundrátb1aa77f2021-12-13 15:16:47 +0100362 (*out)->method.fpath.f = fopen(filepath, "wb");
Radek Krejci84ce7b12020-06-11 17:28:25 +0200363 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100364 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200365 free(*out);
366 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200367 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100368 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200369 (*out)->method.fpath.filepath = strdup(filepath);
370 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100371}
372
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100373LIBYANG_API_DEF const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200374ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100375{
376 FILE *f;
377
Radek Krejci241f6b52020-05-21 18:13:49 +0200378 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100379
380 if (!filepath) {
381 return out->method.fpath.filepath;
382 }
383
384 /* replace filepath */
385 f = out->method.fpath.f;
Jan Kundrátb1aa77f2021-12-13 15:16:47 +0100386 out->method.fpath.f = fopen(filepath, "wb");
Radek Krejcia5bba312020-01-09 15:41:20 +0100387 if (!out->method.fpath.f) {
388 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
389 out->method.fpath.f = f;
Michal Vasko69730152020-10-09 16:30:07 +0200390 return (void *)-1;
Radek Krejcia5bba312020-01-09 15:41:20 +0100391 }
392 fclose(f);
393 free(out->method.fpath.filepath);
394 out->method.fpath.filepath = strdup(filepath);
395
396 return NULL;
397}
398
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100399LIBYANG_API_DEF void
Radek Krejci857189e2020-09-01 13:26:36 +0200400ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100401{
402 if (!out) {
403 return;
404 }
405
406 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200407 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100408 if (clb_arg_destructor) {
409 clb_arg_destructor(out->method.clb.arg);
410 }
411 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200412 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100413 fclose(out->method.fdstream.f);
414 if (destroy) {
415 close(out->method.fdstream.fd);
416 }
417 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200418 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100419 if (destroy) {
420 close(out->method.fd);
421 }
422 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200423 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100424 if (destroy) {
425 fclose(out->method.f);
426 }
427 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200428 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100429 if (destroy) {
430 free(*out->method.mem.buf);
431 }
432 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200433 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100434 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200435 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100436 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200437 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100438 LOGINT(NULL);
439 }
Michal Vasko159b8872020-11-18 18:14:16 +0100440
441 free(out->buffered);
Radek Krejcia5bba312020-01-09 15:41:20 +0100442 free(out);
443}
444
Michal Vasko5233e962020-08-14 14:26:20 +0200445static LY_ERR
446ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200447{
Michal Vasko5233e962020-08-14 14:26:20 +0200448 LY_ERR ret;
449 int written = 0;
Barbaros Tokaogluffc05ea2023-08-12 15:19:11 +0300450 char *msg = NULL;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200451
452 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200453 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200454 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200455 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200456 case LY_OUT_FDSTREAM:
457 case LY_OUT_FILEPATH:
458 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200459 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200460 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200461 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200462 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200463 break;
464 }
Michal Vasko5233e962020-08-14 14:26:20 +0200465 if (out->method.mem.len + written + 1 > out->method.mem.size) {
Barbaros Tokaogluffc05ea2023-08-12 15:19:11 +0300466 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
467 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200468 out->method.mem.len = 0;
469 out->method.mem.size = 0;
optimden3fb41f32024-02-14 15:45:46 +0545470 free(msg);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200471 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200472 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200473 }
Michal Vasko5233e962020-08-14 14:26:20 +0200474 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200475 }
Michal Vasko08e9b112021-06-11 15:41:17 +0200476 if (written) {
477 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
478 }
Michal Vasko5233e962020-08-14 14:26:20 +0200479 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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100525LIBYANG_API_DEF LY_ERR
Michal Vasko5233e962020-08-14 14:26:20 +0200526ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100540LIBYANG_API_DEF 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;
aPiecek61d76952021-08-30 10:28:04 +0200572 size_t written = 0, new_mem_size;
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
Michal Vasko08e9b112021-06-11 15:41:17 +0200587 if (len) {
588 memcpy(&out->buffered[out->buf_len], buf, len);
589 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200590 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200591
592 out->printed += len;
593 out->func_printed += len;
594 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200595 }
596
Radek Krejci897ad2e2019-04-29 16:43:07 +0200597repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200598 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200599 case LY_OUT_MEMORY:
aPiecek61d76952021-08-30 10:28:04 +0200600 new_mem_size = out->method.mem.len + len + 1;
601 if (new_mem_size > out->method.mem.size) {
602 new_mem_size = REALLOC_CHUNK(new_mem_size);
603 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, new_mem_size);
Radek Krejcia5bba312020-01-09 15:41:20 +0100604 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200605 out->method.mem.len = 0;
606 out->method.mem.size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200607 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200608 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200609 }
aPiecek61d76952021-08-30 10:28:04 +0200610 out->method.mem.size = new_mem_size;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200611 }
Michal Vasko08e9b112021-06-11 15:41:17 +0200612 if (len) {
613 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
614 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200615 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100616 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200617
Michal Vasko5233e962020-08-14 14:26:20 +0200618 written = len;
619 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200620 case LY_OUT_FD: {
621 ssize_t r;
Michal Vasko26bbb272022-08-02 14:54:33 +0200622
Radek Krejci1deb5be2020-08-26 16:43:36 +0200623 r = write(out->method.fd, buf, len);
624 if (r < 0) {
625 ret = LY_ESYS;
626 } else {
627 written = (size_t)r;
628 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200629 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200630 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200631 case LY_OUT_FDSTREAM:
632 case LY_OUT_FILEPATH:
633 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200634 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200635 if (written != len) {
636 ret = LY_ESYS;
637 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200638 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200639 case LY_OUT_CALLBACK: {
640 ssize_t r;
Michal Vasko26bbb272022-08-02 14:54:33 +0200641
Radek Krejci1deb5be2020-08-26 16:43:36 +0200642 r = out->method.clb.func(out->method.clb.arg, buf, len);
643 if (r < 0) {
644 ret = LY_ESYS;
645 } else {
646 written = (size_t)r;
647 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200648 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200649 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200650 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100651 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200652 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200653 }
654
Radek Krejci1deb5be2020-08-26 16:43:36 +0200655 if (ret) {
Michal Vasko69730152020-10-09 16:30:07 +0200656 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200657 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200658 goto repeat;
659 }
Michal Vasko5233e962020-08-14 14:26:20 +0200660 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
661 written = 0;
Michal Vasko7b3a00e2023-08-09 11:58:03 +0200662 } else if (written != len) {
663 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %" PRIu32 " from %" PRIu32 " data).", __func__,
664 (uint32_t)(len - written), (uint32_t)len);
Michal Vasko5233e962020-08-14 14:26:20 +0200665 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200666 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200667 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100668 /* move the original file descriptor to the end of the output file */
669 lseek(out->method.fdstream.fd, 0, SEEK_END);
670 }
Michal Vasko5233e962020-08-14 14:26:20 +0200671 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200672 }
Michal Vasko5233e962020-08-14 14:26:20 +0200673
674 out->printed += written;
675 out->func_printed += written;
676 return ret;
677}
678
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100679LIBYANG_API_DEF LY_ERR
Michal Vasko5233e962020-08-14 14:26:20 +0200680ly_write(struct ly_out *out, const char *buf, size_t len)
681{
682 out->func_printed = 0;
683
684 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200685}
686
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100687LIBYANG_API_DEF size_t
Michal Vasko63f3d842020-07-08 10:10:14 +0200688ly_out_printed(const struct ly_out *out)
689{
690 return out->func_printed;
691}
692
Michal Vasko5233e962020-08-14 14:26:20 +0200693LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200694ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200695{
696 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200697 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200698 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100699 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
700 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200701 out->method.mem.len = 0;
702 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200703 LOGMEM(NULL);
704 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200705 }
706 out->method.mem.size = out->method.mem.len + count;
707 }
708
709 /* save the current position */
710 *position = out->method.mem.len;
711
712 /* skip the memory */
713 out->method.mem.len += count;
714 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200715 case LY_OUT_FD:
716 case LY_OUT_FDSTREAM:
717 case LY_OUT_FILEPATH:
718 case LY_OUT_FILE:
719 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200720 /* buffer the hole */
721 if (out->buf_len + count > out->buf_size) {
722 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
723 if (!out->buffered) {
724 out->buf_len = 0;
725 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200726 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200727 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200728 }
729 out->buf_size = out->buf_len + count;
730 }
731
732 /* save the current position */
733 *position = out->buf_len;
734
735 /* skip the memory */
736 out->buf_len += count;
737
738 /* increase hole counter */
739 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100740 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200741 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100742 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200743 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200744 }
745
Michal Vasko5233e962020-08-14 14:26:20 +0200746 /* update printed bytes counter despite we actually printed just a hole */
747 out->printed += count;
748 out->func_printed += count;
749 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200750}
751
Michal Vasko66d99972020-06-29 13:37:42 +0200752LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200753ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200754{
Michal Vasko66d99972020-06-29 13:37:42 +0200755 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200756
Michal Vasko08e9b112021-06-11 15:41:17 +0200757 assert(count);
758
Radek Krejcid3ca0632019-04-16 16:54:54 +0200759 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200760 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200761 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100762 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200763 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200764 case LY_OUT_FD:
765 case LY_OUT_FDSTREAM:
766 case LY_OUT_FILEPATH:
767 case LY_OUT_FILE:
768 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200769 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200770 LOGMEM(NULL);
771 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200772 }
773
774 /* write into the hole */
775 memcpy(&out->buffered[position], buf, count);
776
777 /* decrease hole counter */
778 --out->hole_count;
779
780 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200781 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200782 * printed bytes counter is updated by ly_write_() */
783 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200784 out->buf_len = 0;
785 }
786 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200787 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200788 LOGINT(NULL);
789 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200790 }
791
Radek Krejci241f6b52020-05-21 18:13:49 +0200792 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100793 /* move the original file descriptor to the end of the output file */
794 lseek(out->method.fdstream.fd, 0, SEEK_END);
795 }
Michal Vasko66d99972020-06-29 13:37:42 +0200796 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200797}