blob: 451fba4813bb5561253a7b5445a53b527fbc1f98 [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{
Michal Vaskof77ca9c2024-05-29 13:44:16 +0200110 return !lyd_meta_is_internal(meta);
aPiecek6cf1d162023-11-08 16:07:00 +0100111}
112
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100113LIBYANG_API_DEF LY_OUT_TYPE
Radek Krejci241f6b52020-05-21 18:13:49 +0200114ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100115{
Radek Krejci241f6b52020-05-21 18:13:49 +0200116 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100117 return out->type;
118}
119
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100120LIBYANG_API_DEF LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200121ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100122{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200123 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100124
Radek Krejci84ce7b12020-06-11 17:28:25 +0200125 *out = calloc(1, sizeof **out);
126 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100127
Radek Krejci84ce7b12020-06-11 17:28:25 +0200128 (*out)->type = LY_OUT_CALLBACK;
129 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200130 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100131
Radek Krejci84ce7b12020-06-11 17:28:25 +0200132 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100133}
134
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100135LIBYANG_API_DEF ly_write_clb
Michal Vasko69730152020-10-09 16:30:07 +0200136ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100137{
Michal Vasko59e90fc2021-09-22 12:17:08 +0200138 ly_write_clb prev_clb;
Radek Krejcia5bba312020-01-09 15:41:20 +0100139
Radek Krejci241f6b52020-05-21 18:13:49 +0200140 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100141
142 prev_clb = out->method.clb.func;
143
144 if (writeclb) {
145 out->method.clb.func = writeclb;
146 }
147
148 return prev_clb;
149}
150
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100151LIBYANG_API_DEF void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200152ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100153{
154 void *prev_arg;
155
Radek Krejci241f6b52020-05-21 18:13:49 +0200156 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100157
158 prev_arg = out->method.clb.arg;
159
160 if (arg) {
161 out->method.clb.arg = arg;
162 }
163
164 return prev_arg;
165}
166
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100167LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200168ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100169{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200170 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100171
Radek Krejci84ce7b12020-06-11 17:28:25 +0200172 *out = calloc(1, sizeof **out);
173 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200174 (*out)->type = LY_OUT_FD;
175 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100176
Radek Krejci84ce7b12020-06-11 17:28:25 +0200177 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100178}
179
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100180LIBYANG_API_DEF int
Radek Krejci241f6b52020-05-21 18:13:49 +0200181ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100182{
183 int prev_fd;
184
Radek Krejci241f6b52020-05-21 18:13:49 +0200185 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100186
Radek Krejci241f6b52020-05-21 18:13:49 +0200187 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100188 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200189 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100190 prev_fd = out->method.fd;
191 }
192
193 if (fd != -1) {
194 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200195 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100196 int streamfd;
197 FILE *stream;
198
199 streamfd = dup(fd);
200 if (streamfd < 0) {
201 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
202 return -1;
203 }
204 stream = fdopen(streamfd, "a");
205 if (!stream) {
206 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
207 close(streamfd);
208 return -1;
209 }
210 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
211 fclose(out->method.fdstream.f);
212 out->method.fdstream.f = stream;
213 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200214 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100215 out->method.fd = fd;
216 }
217 }
218
219 return prev_fd;
220}
221
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100222LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200223ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100224{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200225 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100226
Radek Krejci84ce7b12020-06-11 17:28:25 +0200227 *out = calloc(1, sizeof **out);
228 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100229
Radek Krejci84ce7b12020-06-11 17:28:25 +0200230 (*out)->type = LY_OUT_FILE;
231 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100232
Radek Krejci84ce7b12020-06-11 17:28:25 +0200233 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100234}
235
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100236LIBYANG_API_DEF FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200237ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100238{
239 FILE *prev_f;
240
Radek Krejci241f6b52020-05-21 18:13:49 +0200241 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100242
243 prev_f = out->method.f;
244
245 if (f) {
246 out->method.f = f;
247 }
248
249 return prev_f;
250}
251
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100252LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200253ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100254{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200255 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100256
Radek Krejci84ce7b12020-06-11 17:28:25 +0200257 *out = calloc(1, sizeof **out);
258 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100259
Radek Krejci84ce7b12020-06-11 17:28:25 +0200260 (*out)->type = LY_OUT_MEMORY;
261 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100262 if (!size) {
263 /* buffer is supposed to be allocated */
264 *strp = NULL;
265 } else if (*strp) {
266 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200267 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100268 }
269
Radek Krejci84ce7b12020-06-11 17:28:25 +0200270 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100271}
272
273char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200274ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100275{
276 char *data;
277
Radek Krejci241f6b52020-05-21 18:13:49 +0200278 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100279
280 data = *out->method.mem.buf;
281
282 if (strp) {
283 out->method.mem.buf = strp;
284 out->method.mem.len = out->method.mem.size = 0;
285 out->printed = 0;
286 if (!size) {
287 /* buffer is supposed to be allocated */
288 *strp = NULL;
289 } else if (*strp) {
290 /* there is already buffer to use */
291 out->method.mem.size = size;
292 }
293 }
294
295 return data;
296}
297
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100298LIBYANG_API_DEF LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200299ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100300{
301 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
302
Michal Vaskod989ba02020-08-24 10:59:24 +0200303 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200304 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100305 LOGINT(NULL);
306 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200307 case LY_OUT_FD:
Michal Vasko69730152020-10-09 16:30:07 +0200308 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100309 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
310 return LY_ESYS;
311 }
Michal Vasko69730152020-10-09 16:30:07 +0200312 if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200313 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
314 return LY_ESYS;
315 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100316 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200317 case LY_OUT_FDSTREAM:
318 case LY_OUT_FILE:
319 case LY_OUT_FILEPATH:
Michal Vasko69730152020-10-09 16:30:07 +0200320 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100321 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
322 return LY_ESYS;
323 }
Michal Vasko69730152020-10-09 16:30:07 +0200324 if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
Radek Krejcic5a12e12020-05-27 17:09:59 +0200325 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
326 return LY_ESYS;
327 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100328 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200329 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200330 if (out->method.mem.buf && *out->method.mem.buf) {
331 memset(*out->method.mem.buf, 0, out->method.mem.len);
332 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100333 out->printed = 0;
334 out->method.mem.len = 0;
335 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200336 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100337 /* nothing to do (not seekable) */
338 break;
339 }
340
341 return LY_SUCCESS;
342}
343
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100344LIBYANG_API_DEF LY_ERR
Radek Krejci84ce7b12020-06-11 17:28:25 +0200345ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100346{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200347 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100348
Radek Krejci84ce7b12020-06-11 17:28:25 +0200349 *out = calloc(1, sizeof **out);
350 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100351
Radek Krejci84ce7b12020-06-11 17:28:25 +0200352 (*out)->type = LY_OUT_FILEPATH;
Jan Kundrátb1aa77f2021-12-13 15:16:47 +0100353 (*out)->method.fpath.f = fopen(filepath, "wb");
Radek Krejci84ce7b12020-06-11 17:28:25 +0200354 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100355 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200356 free(*out);
357 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200358 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100359 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200360 (*out)->method.fpath.filepath = strdup(filepath);
361 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100362}
363
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100364LIBYANG_API_DEF const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200365ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100366{
367 FILE *f;
368
Radek Krejci241f6b52020-05-21 18:13:49 +0200369 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100370
371 if (!filepath) {
372 return out->method.fpath.filepath;
373 }
374
375 /* replace filepath */
376 f = out->method.fpath.f;
Jan Kundrátb1aa77f2021-12-13 15:16:47 +0100377 out->method.fpath.f = fopen(filepath, "wb");
Radek Krejcia5bba312020-01-09 15:41:20 +0100378 if (!out->method.fpath.f) {
379 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
380 out->method.fpath.f = f;
Michal Vasko69730152020-10-09 16:30:07 +0200381 return (void *)-1;
Radek Krejcia5bba312020-01-09 15:41:20 +0100382 }
383 fclose(f);
384 free(out->method.fpath.filepath);
385 out->method.fpath.filepath = strdup(filepath);
386
387 return NULL;
388}
389
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100390LIBYANG_API_DEF void
Radek Krejci857189e2020-09-01 13:26:36 +0200391ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100392{
393 if (!out) {
394 return;
395 }
396
397 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200398 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100399 if (clb_arg_destructor) {
400 clb_arg_destructor(out->method.clb.arg);
401 }
402 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200403 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100404 fclose(out->method.fdstream.f);
405 if (destroy) {
406 close(out->method.fdstream.fd);
407 }
408 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200409 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100410 if (destroy) {
411 close(out->method.fd);
412 }
413 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200414 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100415 if (destroy) {
416 fclose(out->method.f);
417 }
418 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200419 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100420 if (destroy) {
421 free(*out->method.mem.buf);
422 }
423 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200424 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100425 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200426 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100427 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200428 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100429 LOGINT(NULL);
430 }
Michal Vasko159b8872020-11-18 18:14:16 +0100431
432 free(out->buffered);
Radek Krejcia5bba312020-01-09 15:41:20 +0100433 free(out);
434}
435
Michal Vasko5233e962020-08-14 14:26:20 +0200436static LY_ERR
437ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200438{
Michal Vasko5233e962020-08-14 14:26:20 +0200439 LY_ERR ret;
440 int written = 0;
Barbaros Tokaogluffc05ea2023-08-12 15:19:11 +0300441 char *msg = NULL;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200442
443 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200444 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200445 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200446 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200447 case LY_OUT_FDSTREAM:
448 case LY_OUT_FILEPATH:
449 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200450 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200451 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200452 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200453 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200454 break;
455 }
Michal Vasko5233e962020-08-14 14:26:20 +0200456 if (out->method.mem.len + written + 1 > out->method.mem.size) {
Barbaros Tokaogluffc05ea2023-08-12 15:19:11 +0300457 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
458 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200459 out->method.mem.len = 0;
460 out->method.mem.size = 0;
optimden3fb41f32024-02-14 15:45:46 +0545461 free(msg);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200462 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200463 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200464 }
Michal Vasko5233e962020-08-14 14:26:20 +0200465 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200466 }
Michal Vasko08e9b112021-06-11 15:41:17 +0200467 if (written) {
468 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
469 }
Michal Vasko5233e962020-08-14 14:26:20 +0200470 out->method.mem.len += written;
Radek Krejcia5bba312020-01-09 15:41:20 +0100471 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejcid3ca0632019-04-16 16:54:54 +0200472 free(msg);
473 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200474 case LY_OUT_CALLBACK:
Michal Vasko5233e962020-08-14 14:26:20 +0200475 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200476 break;
477 }
Michal Vasko5233e962020-08-14 14:26:20 +0200478 written = out->method.clb.func(out->method.clb.arg, msg, written);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200479 free(msg);
480 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200481 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100482 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200483 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200484 }
485
Michal Vasko5233e962020-08-14 14:26:20 +0200486 if (written < 0) {
487 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
488 written = 0;
489 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200490 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200491 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100492 /* move the original file descriptor to the end of the output file */
493 lseek(out->method.fdstream.fd, 0, SEEK_END);
494 }
Michal Vasko5233e962020-08-14 14:26:20 +0200495 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200496 }
Michal Vasko5233e962020-08-14 14:26:20 +0200497
498 out->printed += written;
499 out->func_printed += written;
500 return ret;
501}
502
503LY_ERR
504ly_print_(struct ly_out *out, const char *format, ...)
505{
506 LY_ERR ret;
507 va_list ap;
508
509 va_start(ap, format);
510 ret = ly_vprint_(out, format, ap);
511 va_end(ap);
512
513 return ret;
514}
515
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100516LIBYANG_API_DEF LY_ERR
Michal Vasko5233e962020-08-14 14:26:20 +0200517ly_print(struct ly_out *out, const char *format, ...)
518{
519 LY_ERR ret;
520 va_list ap;
521
522 out->func_printed = 0;
523
524 va_start(ap, format);
525 ret = ly_vprint_(out, format, ap);
526 va_end(ap);
527
528 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200529}
530
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100531LIBYANG_API_DEF void
Radek Krejci241f6b52020-05-21 18:13:49 +0200532ly_print_flush(struct ly_out *out)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200533{
534 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200535 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100536 /* move the original file descriptor to the end of the output file */
537 lseek(out->method.fdstream.fd, 0, SEEK_END);
538 fflush(out->method.fdstream.f);
539 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200540 case LY_OUT_FILEPATH:
541 case LY_OUT_FILE:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200542 fflush(out->method.f);
543 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200544 case LY_OUT_FD:
Radek Krejcie7b95092019-05-15 11:03:07 +0200545 fsync(out->method.fd);
546 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200547 case LY_OUT_MEMORY:
548 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200549 /* nothing to do */
550 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200551 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100552 LOGINT(NULL);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200553 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200554
555 free(out->buffered);
556 out->buf_size = out->buf_len = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200557}
558
Michal Vasko5233e962020-08-14 14:26:20 +0200559LY_ERR
560ly_write_(struct ly_out *out, const char *buf, size_t len)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200561{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200562 LY_ERR ret = LY_SUCCESS;
aPiecek61d76952021-08-30 10:28:04 +0200563 size_t written = 0, new_mem_size;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200564
565 if (out->hole_count) {
566 /* we are buffering data after a hole */
Radek Krejcie7b95092019-05-15 11:03:07 +0200567 if (out->buf_len + len > out->buf_size) {
568 out->buffered = ly_realloc(out->buffered, out->buf_len + len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200569 if (!out->buffered) {
570 out->buf_len = 0;
571 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200572 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200573 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200574 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200575 out->buf_size = out->buf_len + len;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200576 }
577
Michal Vasko08e9b112021-06-11 15:41:17 +0200578 if (len) {
579 memcpy(&out->buffered[out->buf_len], buf, len);
580 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200581 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200582
583 out->printed += len;
584 out->func_printed += len;
585 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200586 }
587
Radek Krejci897ad2e2019-04-29 16:43:07 +0200588repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200589 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200590 case LY_OUT_MEMORY:
aPiecek61d76952021-08-30 10:28:04 +0200591 new_mem_size = out->method.mem.len + len + 1;
592 if (new_mem_size > out->method.mem.size) {
593 new_mem_size = REALLOC_CHUNK(new_mem_size);
594 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, new_mem_size);
Radek Krejcia5bba312020-01-09 15:41:20 +0100595 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 }
aPiecek61d76952021-08-30 10:28:04 +0200601 out->method.mem.size = new_mem_size;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200602 }
Michal Vasko08e9b112021-06-11 15:41:17 +0200603 if (len) {
604 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
605 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200606 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100607 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200608
Michal Vasko5233e962020-08-14 14:26:20 +0200609 written = len;
610 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200611 case LY_OUT_FD: {
612 ssize_t r;
Michal Vasko26bbb272022-08-02 14:54:33 +0200613
Radek Krejci1deb5be2020-08-26 16:43:36 +0200614 r = write(out->method.fd, buf, len);
615 if (r < 0) {
616 ret = LY_ESYS;
617 } else {
618 written = (size_t)r;
619 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200620 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200621 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200622 case LY_OUT_FDSTREAM:
623 case LY_OUT_FILEPATH:
624 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200625 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200626 if (written != len) {
627 ret = LY_ESYS;
628 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200629 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200630 case LY_OUT_CALLBACK: {
631 ssize_t r;
Michal Vasko26bbb272022-08-02 14:54:33 +0200632
Radek Krejci1deb5be2020-08-26 16:43:36 +0200633 r = out->method.clb.func(out->method.clb.arg, buf, len);
634 if (r < 0) {
635 ret = LY_ESYS;
636 } else {
637 written = (size_t)r;
638 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200639 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200640 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200641 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100642 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200643 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200644 }
645
Radek Krejci1deb5be2020-08-26 16:43:36 +0200646 if (ret) {
Michal Vasko69730152020-10-09 16:30:07 +0200647 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200648 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200649 goto repeat;
650 }
Michal Vasko5233e962020-08-14 14:26:20 +0200651 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
652 written = 0;
Michal Vasko7b3a00e2023-08-09 11:58:03 +0200653 } else if (written != len) {
654 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %" PRIu32 " from %" PRIu32 " data).", __func__,
655 (uint32_t)(len - written), (uint32_t)len);
Michal Vasko5233e962020-08-14 14:26:20 +0200656 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200657 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200658 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100659 /* move the original file descriptor to the end of the output file */
660 lseek(out->method.fdstream.fd, 0, SEEK_END);
661 }
Michal Vasko5233e962020-08-14 14:26:20 +0200662 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200663 }
Michal Vasko5233e962020-08-14 14:26:20 +0200664
665 out->printed += written;
666 out->func_printed += written;
667 return ret;
668}
669
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100670LIBYANG_API_DEF LY_ERR
Michal Vasko5233e962020-08-14 14:26:20 +0200671ly_write(struct ly_out *out, const char *buf, size_t len)
672{
673 out->func_printed = 0;
674
675 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200676}
677
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100678LIBYANG_API_DEF size_t
Michal Vasko63f3d842020-07-08 10:10:14 +0200679ly_out_printed(const struct ly_out *out)
680{
681 return out->func_printed;
682}
683
Michal Vasko5233e962020-08-14 14:26:20 +0200684LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200685ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200686{
687 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200688 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200689 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100690 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
691 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200692 out->method.mem.len = 0;
693 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200694 LOGMEM(NULL);
695 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200696 }
697 out->method.mem.size = out->method.mem.len + count;
698 }
699
700 /* save the current position */
701 *position = out->method.mem.len;
702
703 /* skip the memory */
704 out->method.mem.len += count;
705 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200706 case LY_OUT_FD:
707 case LY_OUT_FDSTREAM:
708 case LY_OUT_FILEPATH:
709 case LY_OUT_FILE:
710 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200711 /* buffer the hole */
712 if (out->buf_len + count > out->buf_size) {
713 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
714 if (!out->buffered) {
715 out->buf_len = 0;
716 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200717 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200718 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200719 }
720 out->buf_size = out->buf_len + count;
721 }
722
723 /* save the current position */
724 *position = out->buf_len;
725
726 /* skip the memory */
727 out->buf_len += count;
728
729 /* increase hole counter */
730 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100731 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200732 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100733 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200734 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200735 }
736
Michal Vasko5233e962020-08-14 14:26:20 +0200737 /* update printed bytes counter despite we actually printed just a hole */
738 out->printed += count;
739 out->func_printed += count;
740 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200741}
742
Michal Vasko66d99972020-06-29 13:37:42 +0200743LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200744ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200745{
Michal Vasko66d99972020-06-29 13:37:42 +0200746 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200747
Michal Vasko08e9b112021-06-11 15:41:17 +0200748 assert(count);
749
Radek Krejcid3ca0632019-04-16 16:54:54 +0200750 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200751 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200752 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100753 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200754 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200755 case LY_OUT_FD:
756 case LY_OUT_FDSTREAM:
757 case LY_OUT_FILEPATH:
758 case LY_OUT_FILE:
759 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200760 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200761 LOGMEM(NULL);
762 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200763 }
764
765 /* write into the hole */
766 memcpy(&out->buffered[position], buf, count);
767
768 /* decrease hole counter */
769 --out->hole_count;
770
771 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200772 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200773 * printed bytes counter is updated by ly_write_() */
774 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200775 out->buf_len = 0;
776 }
777 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200778 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200779 LOGINT(NULL);
780 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200781 }
782
Radek Krejci241f6b52020-05-21 18:13:49 +0200783 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100784 /* move the original file descriptor to the end of the output file */
785 lseek(out->method.fdstream.fd, 0, SEEK_END);
786 }
Michal Vasko66d99972020-06-29 13:37:42 +0200787 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200788}