blob: def1fa876eeb7f7d509a59ddc30f0373ef409612 [file] [log] [blame]
Radek Krejcid3ca0632019-04-16 16:54:54 +02001/**
2 * @file printer.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Radek Krejcie7b95092019-05-15 11:03:07 +02004 * @brief Generic libyang printers functions.
Radek Krejcid3ca0632019-04-16 16:54:54 +02005 *
6 * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Radek Krejcid3ca0632019-04-16 16:54:54 +020016
Radek Krejci535ea9f2020-05-29 16:01:05 +020017#include "printer.h"
18
19#include <assert.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020020#include <errno.h>
21#include <stdarg.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdio.h>
23#include <stdlib.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020024#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include <unistd.h>
Radek Krejcid3ca0632019-04-16 16:54:54 +020026
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020028#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "log.h"
Michal Vasko9b368d32020-02-14 13:53:31 +010030#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "printer_data.h"
32#include "printer_internal.h"
33#include "tree.h"
34#include "tree_schema.h"
Radek Krejcid3ca0632019-04-16 16:54:54 +020035
36/**
37 * @brief informational structure shared by printers
38 */
39struct ext_substmt_info_s ext_substmt_info[] = {
Radek Krejci0f969882020-08-21 16:56:47 +020040 {NULL, NULL, 0}, /**< LYEXT_SUBSTMT_SELF */
41 {"argument", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ARGUMENT */
42 {"base", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BASE */
43 {"belongs-to", "module", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BELONGSTO */
44 {"contact", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_CONTACT */
45 {"default", "value", 0}, /**< LYEXT_SUBSTMT_DEFAULT */
46 {"description", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_DESCRIPTION */
47 {"error-app-tag", "value", 0}, /**< LYEXT_SUBSTMT_ERRTAG */
48 {"error-message", "value", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ERRMSG */
49 {"key", "value", 0}, /**< LYEXT_SUBSTMT_KEY */
50 {"namespace", "uri", 0}, /**< LYEXT_SUBSTMT_NAMESPACE */
51 {"organization", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ORGANIZATION */
52 {"path", "value", 0}, /**< LYEXT_SUBSTMT_PATH */
53 {"prefix", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_PREFIX */
54 {"presence", "value", 0}, /**< LYEXT_SUBSTMT_PRESENCE */
55 {"reference", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_REFERENCE */
56 {"revision-date", "date", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REVISIONDATE */
57 {"units", "name", 0}, /**< LYEXT_SUBSTMT_UNITS */
58 {"value", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VALUE */
59 {"yang-version", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VERSION */
60 {"modifier", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MODIFIER */
61 {"require-instance", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REQINST */
62 {"yin-element", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_YINELEM */
63 {"config", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_CONFIG */
64 {"mandatory", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MANDATORY */
65 {"ordered-by", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ORDEREDBY */
66 {"status", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_STATUS */
67 {"fraction-digits", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_DIGITS */
68 {"max-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MAX */
69 {"min-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MIN */
70 {"position", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_POSITION */
71 {"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
Radek Krejcid3ca0632019-04-16 16:54:54 +020072};
73
Radek Krejci857189e2020-09-01 13:26:36 +020074ly_bool
Michal Vasko9b368d32020-02-14 13:53:31 +010075ly_is_default(const struct lyd_node *node)
76{
77 const struct lysc_node_leaf *leaf;
78 const struct lysc_node_leaflist *llist;
79 const struct lyd_node_term *term;
Michal Vaskofd69e1d2020-07-03 11:57:17 +020080 LY_ARRAY_COUNT_TYPE u;
Michal Vasko9b368d32020-02-14 13:53:31 +010081
82 assert(node->schema->nodetype & LYD_NODE_TERM);
83 term = (const struct lyd_node_term *)node;
84
85 if (node->schema->nodetype == LYS_LEAF) {
86 leaf = (const struct lysc_node_leaf *)node->schema;
87 if (!leaf->dflt) {
88 return 0;
89 }
90
91 /* compare with the default value */
92 if (leaf->type->plugin->compare(&term->value, leaf->dflt)) {
93 return 0;
94 }
95 } else {
96 llist = (const struct lysc_node_leaflist *)node->schema;
97 if (!llist->dflts) {
98 return 0;
99 }
100
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200101 LY_ARRAY_FOR(llist->dflts, u) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100102 /* compare with each possible default value */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200103 if (llist->type->plugin->compare(&term->value, llist->dflts[u])) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100104 return 0;
105 }
106 }
107 }
108
109 return 1;
110}
111
Radek Krejci857189e2020-09-01 13:26:36 +0200112ly_bool
Radek Krejci1deb5be2020-08-26 16:43:36 +0200113ly_should_print(const struct lyd_node *node, uint32_t options)
Michal Vasko9b368d32020-02-14 13:53:31 +0100114{
Michal Vasko56daf732020-08-10 10:57:18 +0200115 const struct lyd_node *elem;
Michal Vasko9b368d32020-02-14 13:53:31 +0100116
Radek Krejci7931b192020-06-25 17:05:03 +0200117 if (options & LYD_PRINT_WD_TRIM) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100118 /* do not print default nodes */
119 if (node->flags & LYD_DEFAULT) {
120 /* implicit default node/NP container with only default nodes */
121 return 0;
122 } else if (node->schema->nodetype & LYD_NODE_TERM) {
123 if (ly_is_default(node)) {
124 /* explicit default node */
125 return 0;
126 }
127 }
Radek Krejci7931b192020-06-25 17:05:03 +0200128 } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200129 /* LYDP_WD_EXPLICIT
Michal Vasko9b368d32020-02-14 13:53:31 +0100130 * - print only if it contains status data in its subtree */
Michal Vasko56daf732020-08-10 10:57:18 +0200131 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vaskodb4f9e42020-06-01 17:29:56 +0200132 if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
133 if (elem->schema->flags & LYS_CONFIG_R) {
134 return 1;
135 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100136 }
Michal Vasko56daf732020-08-10 10:57:18 +0200137 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100138 }
139 return 0;
Radek Krejci7931b192020-06-25 17:05:03 +0200140 } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYD_PRINT_KEEPEMPTYCONT)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100141 /* avoid empty default containers */
Michal Vasko56daf732020-08-10 10:57:18 +0200142 LYD_TREE_DFS_BEGIN(node, elem) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100143 if (elem->schema->nodetype != LYS_CONTAINER) {
144 return 1;
145 }
146 assert(elem->flags & LYD_DEFAULT);
Michal Vasko56daf732020-08-10 10:57:18 +0200147 LYD_TREE_DFS_END(node, elem)
Michal Vasko9b368d32020-02-14 13:53:31 +0100148 }
149 return 0;
150 }
151
152 return 1;
153}
154
Radek Krejci241f6b52020-05-21 18:13:49 +0200155API LY_OUT_TYPE
156ly_out_type(const struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100157{
Radek Krejci241f6b52020-05-21 18:13:49 +0200158 LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
Radek Krejcia5bba312020-01-09 15:41:20 +0100159 return out->type;
160}
161
Radek Krejci84ce7b12020-06-11 17:28:25 +0200162API LY_ERR
Michal Vaskoce2b8742020-08-24 13:20:25 +0200163ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100164{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200165 LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100166
Radek Krejci84ce7b12020-06-11 17:28:25 +0200167 *out = calloc(1, sizeof **out);
168 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100169
Radek Krejci84ce7b12020-06-11 17:28:25 +0200170 (*out)->type = LY_OUT_CALLBACK;
171 (*out)->method.clb.func = writeclb;
Michal Vaskoce2b8742020-08-24 13:20:25 +0200172 (*out)->method.clb.arg = user_data;
Radek Krejcia5bba312020-01-09 15:41:20 +0100173
Radek Krejci84ce7b12020-06-11 17:28:25 +0200174 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100175}
176
Michal Vaskoce2b8742020-08-24 13:20:25 +0200177API ly_write_clb ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
Radek Krejcia5bba312020-01-09 15:41:20 +0100178{
179 void *prev_clb;
180
Radek Krejci241f6b52020-05-21 18:13:49 +0200181 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100182
183 prev_clb = out->method.clb.func;
184
185 if (writeclb) {
186 out->method.clb.func = writeclb;
187 }
188
189 return prev_clb;
190}
191
192API void *
Radek Krejci241f6b52020-05-21 18:13:49 +0200193ly_out_clb_arg(struct ly_out *out, void *arg)
Radek Krejcia5bba312020-01-09 15:41:20 +0100194{
195 void *prev_arg;
196
Radek Krejci241f6b52020-05-21 18:13:49 +0200197 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100198
199 prev_arg = out->method.clb.arg;
200
201 if (arg) {
202 out->method.clb.arg = arg;
203 }
204
205 return prev_arg;
206}
207
Radek Krejci84ce7b12020-06-11 17:28:25 +0200208API LY_ERR
209ly_out_new_fd(int fd, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100210{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200211 LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100212
Radek Krejci84ce7b12020-06-11 17:28:25 +0200213 *out = calloc(1, sizeof **out);
214 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejci84ce7b12020-06-11 17:28:25 +0200215 (*out)->type = LY_OUT_FD;
216 (*out)->method.fd = fd;
Radek Krejcia5bba312020-01-09 15:41:20 +0100217
Radek Krejci84ce7b12020-06-11 17:28:25 +0200218 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100219}
220
221API int
Radek Krejci241f6b52020-05-21 18:13:49 +0200222ly_out_fd(struct ly_out *out, int fd)
Radek Krejcia5bba312020-01-09 15:41:20 +0100223{
224 int prev_fd;
225
Radek Krejci241f6b52020-05-21 18:13:49 +0200226 LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
Radek Krejcia5bba312020-01-09 15:41:20 +0100227
Radek Krejci241f6b52020-05-21 18:13:49 +0200228 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100229 prev_fd = out->method.fdstream.fd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200230 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100231 prev_fd = out->method.fd;
232 }
233
234 if (fd != -1) {
235 /* replace output stream */
Radek Krejci241f6b52020-05-21 18:13:49 +0200236 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100237 int streamfd;
238 FILE *stream;
239
240 streamfd = dup(fd);
241 if (streamfd < 0) {
242 LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
243 return -1;
244 }
245 stream = fdopen(streamfd, "a");
246 if (!stream) {
247 LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
248 close(streamfd);
249 return -1;
250 }
251 /* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
252 fclose(out->method.fdstream.f);
253 out->method.fdstream.f = stream;
254 out->method.fdstream.fd = streamfd;
Radek Krejci241f6b52020-05-21 18:13:49 +0200255 } else { /* LY_OUT_FD */
Radek Krejcia5bba312020-01-09 15:41:20 +0100256 out->method.fd = fd;
257 }
258 }
259
260 return prev_fd;
261}
262
Radek Krejci84ce7b12020-06-11 17:28:25 +0200263API LY_ERR
264ly_out_new_file(FILE *f, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100265{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200266 LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100267
Radek Krejci84ce7b12020-06-11 17:28:25 +0200268 *out = calloc(1, sizeof **out);
269 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100270
Radek Krejci84ce7b12020-06-11 17:28:25 +0200271 (*out)->type = LY_OUT_FILE;
272 (*out)->method.f = f;
Radek Krejcia5bba312020-01-09 15:41:20 +0100273
Radek Krejci84ce7b12020-06-11 17:28:25 +0200274 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100275}
276
277API FILE *
Radek Krejci241f6b52020-05-21 18:13:49 +0200278ly_out_file(struct ly_out *out, FILE *f)
Radek Krejcia5bba312020-01-09 15:41:20 +0100279{
280 FILE *prev_f;
281
Radek Krejci241f6b52020-05-21 18:13:49 +0200282 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100283
284 prev_f = out->method.f;
285
286 if (f) {
287 out->method.f = f;
288 }
289
290 return prev_f;
291}
292
Radek Krejci84ce7b12020-06-11 17:28:25 +0200293API LY_ERR
294ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100295{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200296 LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100297
Radek Krejci84ce7b12020-06-11 17:28:25 +0200298 *out = calloc(1, sizeof **out);
299 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100300
Radek Krejci84ce7b12020-06-11 17:28:25 +0200301 (*out)->type = LY_OUT_MEMORY;
302 (*out)->method.mem.buf = strp;
Radek Krejcia5bba312020-01-09 15:41:20 +0100303 if (!size) {
304 /* buffer is supposed to be allocated */
305 *strp = NULL;
306 } else if (*strp) {
307 /* there is already buffer to use */
Radek Krejci84ce7b12020-06-11 17:28:25 +0200308 (*out)->method.mem.size = size;
Radek Krejcia5bba312020-01-09 15:41:20 +0100309 }
310
Radek Krejci84ce7b12020-06-11 17:28:25 +0200311 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100312}
313
314char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200315ly_out_memory(struct ly_out *out, char **strp, size_t size)
Radek Krejcia5bba312020-01-09 15:41:20 +0100316{
317 char *data;
318
Radek Krejci241f6b52020-05-21 18:13:49 +0200319 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100320
321 data = *out->method.mem.buf;
322
323 if (strp) {
324 out->method.mem.buf = strp;
325 out->method.mem.len = out->method.mem.size = 0;
326 out->printed = 0;
327 if (!size) {
328 /* buffer is supposed to be allocated */
329 *strp = NULL;
330 } else if (*strp) {
331 /* there is already buffer to use */
332 out->method.mem.size = size;
333 }
334 }
335
336 return data;
337}
338
339API LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200340ly_out_reset(struct ly_out *out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100341{
342 LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
343
Michal Vaskod989ba02020-08-24 10:59:24 +0200344 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200345 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100346 LOGINT(NULL);
347 return LY_EINT;
Radek Krejci241f6b52020-05-21 18:13:49 +0200348 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100349 if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && errno != ESPIPE) {
350 LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
351 return LY_ESYS;
352 }
Radek Krejcic5a12e12020-05-27 17:09:59 +0200353 if (errno != ESPIPE && ftruncate(out->method.fd, 0) == -1) {
354 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
355 return LY_ESYS;
356 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100357 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200358 case LY_OUT_FDSTREAM:
359 case LY_OUT_FILE:
360 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100361 if ((fseek(out->method.f, 0, SEEK_SET) == -1) && errno != ESPIPE) {
362 LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
363 return LY_ESYS;
364 }
Radek Krejcic5a12e12020-05-27 17:09:59 +0200365 if (errno != ESPIPE && ftruncate(fileno(out->method.f), 0) == -1) {
366 LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
367 return LY_ESYS;
368 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100369 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200370 case LY_OUT_MEMORY:
Radek Krejcic5a12e12020-05-27 17:09:59 +0200371 if (out->method.mem.buf && *out->method.mem.buf) {
372 memset(*out->method.mem.buf, 0, out->method.mem.len);
373 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100374 out->printed = 0;
375 out->method.mem.len = 0;
376 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200377 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100378 /* nothing to do (not seekable) */
379 break;
380 }
381
382 return LY_SUCCESS;
383}
384
Radek Krejci84ce7b12020-06-11 17:28:25 +0200385API LY_ERR
386ly_out_new_filepath(const char *filepath, struct ly_out **out)
Radek Krejcia5bba312020-01-09 15:41:20 +0100387{
Radek Krejci84ce7b12020-06-11 17:28:25 +0200388 LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
Radek Krejcia5bba312020-01-09 15:41:20 +0100389
Radek Krejci84ce7b12020-06-11 17:28:25 +0200390 *out = calloc(1, sizeof **out);
391 LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
Radek Krejcia5bba312020-01-09 15:41:20 +0100392
Radek Krejci84ce7b12020-06-11 17:28:25 +0200393 (*out)->type = LY_OUT_FILEPATH;
394 (*out)->method.fpath.f = fopen(filepath, "w");
395 if (!(*out)->method.fpath.f) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100396 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
Radek Krejcif6923e82020-07-02 16:36:53 +0200397 free(*out);
398 *out = NULL;
Radek Krejci84ce7b12020-06-11 17:28:25 +0200399 return LY_ESYS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100400 }
Radek Krejci84ce7b12020-06-11 17:28:25 +0200401 (*out)->method.fpath.filepath = strdup(filepath);
402 return LY_SUCCESS;
Radek Krejcia5bba312020-01-09 15:41:20 +0100403}
404
405API const char *
Radek Krejci241f6b52020-05-21 18:13:49 +0200406ly_out_filepath(struct ly_out *out, const char *filepath)
Radek Krejcia5bba312020-01-09 15:41:20 +0100407{
408 FILE *f;
409
Radek Krejci241f6b52020-05-21 18:13:49 +0200410 LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
Radek Krejcia5bba312020-01-09 15:41:20 +0100411
412 if (!filepath) {
413 return out->method.fpath.filepath;
414 }
415
416 /* replace filepath */
417 f = out->method.fpath.f;
418 out->method.fpath.f = fopen(filepath, "w");
419 if (!out->method.fpath.f) {
420 LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
421 out->method.fpath.f = f;
422 return ((void *)-1);
423 }
424 fclose(f);
425 free(out->method.fpath.filepath);
426 out->method.fpath.filepath = strdup(filepath);
427
428 return NULL;
429}
430
431API void
Radek Krejci857189e2020-09-01 13:26:36 +0200432ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
Radek Krejcia5bba312020-01-09 15:41:20 +0100433{
434 if (!out) {
435 return;
436 }
437
438 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200439 case LY_OUT_CALLBACK:
Radek Krejcia5bba312020-01-09 15:41:20 +0100440 if (clb_arg_destructor) {
441 clb_arg_destructor(out->method.clb.arg);
442 }
443 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200444 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100445 fclose(out->method.fdstream.f);
446 if (destroy) {
447 close(out->method.fdstream.fd);
448 }
449 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200450 case LY_OUT_FD:
Radek Krejcia5bba312020-01-09 15:41:20 +0100451 if (destroy) {
452 close(out->method.fd);
453 }
454 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200455 case LY_OUT_FILE:
Radek Krejcia5bba312020-01-09 15:41:20 +0100456 if (destroy) {
457 fclose(out->method.f);
458 }
459 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200460 case LY_OUT_MEMORY:
Radek Krejcia5bba312020-01-09 15:41:20 +0100461 if (destroy) {
462 free(*out->method.mem.buf);
463 }
464 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200465 case LY_OUT_FILEPATH:
Radek Krejcia5bba312020-01-09 15:41:20 +0100466 free(out->method.fpath.filepath);
Radek Krejci2aae3752020-05-27 18:16:30 +0200467 fclose(out->method.fpath.f);
Radek Krejcia5bba312020-01-09 15:41:20 +0100468 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200469 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100470 LOGINT(NULL);
471 }
472 free(out);
473}
474
Michal Vasko5233e962020-08-14 14:26:20 +0200475static LY_ERR
476ly_vprint_(struct ly_out *out, const char *format, va_list ap)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200477{
Michal Vasko5233e962020-08-14 14:26:20 +0200478 LY_ERR ret;
479 int written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200480 char *msg = NULL, *aux;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200481
482 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200483 case LY_OUT_FD:
Michal Vasko5233e962020-08-14 14:26:20 +0200484 written = vdprintf(out->method.fd, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200485 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200486 case LY_OUT_FDSTREAM:
487 case LY_OUT_FILEPATH:
488 case LY_OUT_FILE:
Michal Vasko5233e962020-08-14 14:26:20 +0200489 written = vfprintf(out->method.f, format, ap);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200490 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200491 case LY_OUT_MEMORY:
Michal Vasko5233e962020-08-14 14:26:20 +0200492 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200493 break;
494 }
Michal Vasko5233e962020-08-14 14:26:20 +0200495 if (out->method.mem.len + written + 1 > out->method.mem.size) {
496 aux = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200497 if (!aux) {
498 out->method.mem.buf = NULL;
499 out->method.mem.len = 0;
500 out->method.mem.size = 0;
501 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200502 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200503 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100504 *out->method.mem.buf = aux;
Michal Vasko5233e962020-08-14 14:26:20 +0200505 out->method.mem.size = out->method.mem.len + written + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200506 }
Michal Vasko5233e962020-08-14 14:26:20 +0200507 memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
508 out->method.mem.len += written;
Radek Krejcia5bba312020-01-09 15:41:20 +0100509 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejcid3ca0632019-04-16 16:54:54 +0200510 free(msg);
511 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200512 case LY_OUT_CALLBACK:
Michal Vasko5233e962020-08-14 14:26:20 +0200513 if ((written = vasprintf(&msg, format, ap)) < 0) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200514 break;
515 }
Michal Vasko5233e962020-08-14 14:26:20 +0200516 written = out->method.clb.func(out->method.clb.arg, msg, written);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200517 free(msg);
518 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200519 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100520 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200521 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200522 }
523
Michal Vasko5233e962020-08-14 14:26:20 +0200524 if (written < 0) {
525 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
526 written = 0;
527 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200528 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200529 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100530 /* move the original file descriptor to the end of the output file */
531 lseek(out->method.fdstream.fd, 0, SEEK_END);
532 }
Michal Vasko5233e962020-08-14 14:26:20 +0200533 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200534 }
Michal Vasko5233e962020-08-14 14:26:20 +0200535
536 out->printed += written;
537 out->func_printed += written;
538 return ret;
539}
540
541LY_ERR
542ly_print_(struct ly_out *out, const char *format, ...)
543{
544 LY_ERR ret;
545 va_list ap;
546
547 va_start(ap, format);
548 ret = ly_vprint_(out, format, ap);
549 va_end(ap);
550
551 return ret;
552}
553
554API LY_ERR
555ly_print(struct ly_out *out, const char *format, ...)
556{
557 LY_ERR ret;
558 va_list ap;
559
560 out->func_printed = 0;
561
562 va_start(ap, format);
563 ret = ly_vprint_(out, format, ap);
564 va_end(ap);
565
566 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200567}
568
Radek Krejci2aae3752020-05-27 18:16:30 +0200569API void
Radek Krejci241f6b52020-05-21 18:13:49 +0200570ly_print_flush(struct ly_out *out)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200571{
572 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200573 case LY_OUT_FDSTREAM:
Radek Krejcia5bba312020-01-09 15:41:20 +0100574 /* move the original file descriptor to the end of the output file */
575 lseek(out->method.fdstream.fd, 0, SEEK_END);
576 fflush(out->method.fdstream.f);
577 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200578 case LY_OUT_FILEPATH:
579 case LY_OUT_FILE:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200580 fflush(out->method.f);
581 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200582 case LY_OUT_FD:
Radek Krejcie7b95092019-05-15 11:03:07 +0200583 fsync(out->method.fd);
584 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200585 case LY_OUT_MEMORY:
586 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200587 /* nothing to do */
588 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200589 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100590 LOGINT(NULL);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200591 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200592
593 free(out->buffered);
594 out->buf_size = out->buf_len = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200595}
596
Michal Vasko5233e962020-08-14 14:26:20 +0200597LY_ERR
598ly_write_(struct ly_out *out, const char *buf, size_t len)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200599{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200600 LY_ERR ret = LY_SUCCESS;
601 size_t written = 0;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200602
603 if (out->hole_count) {
604 /* we are buffering data after a hole */
Radek Krejcie7b95092019-05-15 11:03:07 +0200605 if (out->buf_len + len > out->buf_size) {
606 out->buffered = ly_realloc(out->buffered, out->buf_len + len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200607 if (!out->buffered) {
608 out->buf_len = 0;
609 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200610 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200611 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200612 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200613 out->buf_size = out->buf_len + len;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200614 }
615
Radek Krejcie7b95092019-05-15 11:03:07 +0200616 memcpy(&out->buffered[out->buf_len], buf, len);
617 out->buf_len += len;
Michal Vasko5233e962020-08-14 14:26:20 +0200618
619 out->printed += len;
620 out->func_printed += len;
621 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200622 }
623
Radek Krejci897ad2e2019-04-29 16:43:07 +0200624repeat:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200625 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200626 case LY_OUT_MEMORY:
Radek Krejcie7b95092019-05-15 11:03:07 +0200627 if (out->method.mem.len + len + 1 > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100628 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + len + 1);
629 if (!*out->method.mem.buf) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200630 out->method.mem.len = 0;
631 out->method.mem.size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200632 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200633 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200634 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200635 out->method.mem.size = out->method.mem.len + len + 1;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200636 }
Radek Krejcia5bba312020-01-09 15:41:20 +0100637 memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200638 out->method.mem.len += len;
Radek Krejcia5bba312020-01-09 15:41:20 +0100639 (*out->method.mem.buf)[out->method.mem.len] = '\0';
Radek Krejci897ad2e2019-04-29 16:43:07 +0200640
Michal Vasko5233e962020-08-14 14:26:20 +0200641 written = len;
642 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200643 case LY_OUT_FD: {
644 ssize_t r;
645 r = write(out->method.fd, buf, len);
646 if (r < 0) {
647 ret = LY_ESYS;
648 } else {
649 written = (size_t)r;
650 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200651 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200652 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200653 case LY_OUT_FDSTREAM:
654 case LY_OUT_FILEPATH:
655 case LY_OUT_FILE:
Michal Vasko63f3d842020-07-08 10:10:14 +0200656 written = fwrite(buf, sizeof *buf, len, out->method.f);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200657 if (written != len) {
658 ret = LY_ESYS;
659 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200660 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200661 case LY_OUT_CALLBACK: {
662 ssize_t r;
663 r = out->method.clb.func(out->method.clb.arg, buf, len);
664 if (r < 0) {
665 ret = LY_ESYS;
666 } else {
667 written = (size_t)r;
668 }
Radek Krejcid3ca0632019-04-16 16:54:54 +0200669 break;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200670 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200671 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100672 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200673 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200674 }
675
Radek Krejci1deb5be2020-08-26 16:43:36 +0200676 if (ret) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200677 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200678 ret = LY_SUCCESS;
Radek Krejci897ad2e2019-04-29 16:43:07 +0200679 goto repeat;
680 }
Michal Vasko5233e962020-08-14 14:26:20 +0200681 LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
682 written = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200683 } else if ((size_t)written != len) {
Michal Vasko5233e962020-08-14 14:26:20 +0200684 LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__,
Michal Vasko63f3d842020-07-08 10:10:14 +0200685 len - (size_t)written, len);
Michal Vasko5233e962020-08-14 14:26:20 +0200686 ret = LY_ESYS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200687 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200688 if (out->type == LY_OUT_FDSTREAM) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100689 /* move the original file descriptor to the end of the output file */
690 lseek(out->method.fdstream.fd, 0, SEEK_END);
691 }
Michal Vasko5233e962020-08-14 14:26:20 +0200692 ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200693 }
Michal Vasko5233e962020-08-14 14:26:20 +0200694
695 out->printed += written;
696 out->func_printed += written;
697 return ret;
698}
699
700API LY_ERR
701ly_write(struct ly_out *out, const char *buf, size_t len)
702{
703 out->func_printed = 0;
704
705 return ly_write_(out, buf, len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200706}
707
Michal Vasko63f3d842020-07-08 10:10:14 +0200708API size_t
709ly_out_printed(const struct ly_out *out)
710{
711 return out->func_printed;
712}
713
Michal Vasko5233e962020-08-14 14:26:20 +0200714LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200715ly_write_skip(struct ly_out *out, size_t count, size_t *position)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200716{
717 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200718 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200719 if (out->method.mem.len + count > out->method.mem.size) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100720 *out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
721 if (!(*out->method.mem.buf)) {
Radek Krejcid3ca0632019-04-16 16:54:54 +0200722 out->method.mem.len = 0;
723 out->method.mem.size = 0;
Michal Vasko5233e962020-08-14 14:26:20 +0200724 LOGMEM(NULL);
725 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200726 }
727 out->method.mem.size = out->method.mem.len + count;
728 }
729
730 /* save the current position */
731 *position = out->method.mem.len;
732
733 /* skip the memory */
734 out->method.mem.len += count;
735 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200736 case LY_OUT_FD:
737 case LY_OUT_FDSTREAM:
738 case LY_OUT_FILEPATH:
739 case LY_OUT_FILE:
740 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200741 /* buffer the hole */
742 if (out->buf_len + count > out->buf_size) {
743 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
744 if (!out->buffered) {
745 out->buf_len = 0;
746 out->buf_size = 0;
Radek Krejcibaeb8382020-05-27 16:44:53 +0200747 LOGMEM(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200748 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200749 }
750 out->buf_size = out->buf_len + count;
751 }
752
753 /* save the current position */
754 *position = out->buf_len;
755
756 /* skip the memory */
757 out->buf_len += count;
758
759 /* increase hole counter */
760 ++out->hole_count;
Radek Krejcia5bba312020-01-09 15:41:20 +0100761 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200762 case LY_OUT_ERROR:
Radek Krejcia5bba312020-01-09 15:41:20 +0100763 LOGINT(NULL);
Michal Vasko5233e962020-08-14 14:26:20 +0200764 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200765 }
766
Michal Vasko5233e962020-08-14 14:26:20 +0200767 /* update printed bytes counter despite we actually printed just a hole */
768 out->printed += count;
769 out->func_printed += count;
770 return LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200771}
772
Michal Vasko66d99972020-06-29 13:37:42 +0200773LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200774ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
Radek Krejcid3ca0632019-04-16 16:54:54 +0200775{
Michal Vasko66d99972020-06-29 13:37:42 +0200776 LY_ERR ret = LY_SUCCESS;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200777
778 switch (out->type) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200779 case LY_OUT_MEMORY:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200780 /* write */
Radek Krejcia5bba312020-01-09 15:41:20 +0100781 memcpy(&(*out->method.mem.buf)[position], buf, count);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200782 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200783 case LY_OUT_FD:
784 case LY_OUT_FDSTREAM:
785 case LY_OUT_FILEPATH:
786 case LY_OUT_FILE:
787 case LY_OUT_CALLBACK:
Radek Krejcid3ca0632019-04-16 16:54:54 +0200788 if (out->buf_len < position + count) {
Michal Vasko5233e962020-08-14 14:26:20 +0200789 LOGMEM(NULL);
790 return LY_EMEM;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200791 }
792
793 /* write into the hole */
794 memcpy(&out->buffered[position], buf, count);
795
796 /* decrease hole counter */
797 --out->hole_count;
798
799 if (!out->hole_count) {
Radek Krejci897ad2e2019-04-29 16:43:07 +0200800 /* all holes filled, we can write the buffer,
Michal Vasko5233e962020-08-14 14:26:20 +0200801 * printed bytes counter is updated by ly_write_() */
802 ret = ly_write_(out, out->buffered, out->buf_len);
Radek Krejcid3ca0632019-04-16 16:54:54 +0200803 out->buf_len = 0;
804 }
805 break;
Radek Krejci241f6b52020-05-21 18:13:49 +0200806 case LY_OUT_ERROR:
Michal Vasko5233e962020-08-14 14:26:20 +0200807 LOGINT(NULL);
808 return LY_EINT;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200809 }
810
Radek Krejci241f6b52020-05-21 18:13:49 +0200811 if (out->type == LY_OUT_FILEPATH) {
Radek Krejcia5bba312020-01-09 15:41:20 +0100812 /* move the original file descriptor to the end of the output file */
813 lseek(out->method.fdstream.fd, 0, SEEK_END);
814 }
Michal Vasko66d99972020-06-29 13:37:42 +0200815 return ret;
Radek Krejcid3ca0632019-04-16 16:54:54 +0200816}