wma_afh: Fix two bugs in convert_utf8_to_utf16().
[paraslash.git] / stdout.c
1 /*
2  * Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file stdout.c Functions that deal with writing to stdout. */
8
9 #include "para.h"
10 #include "list.h"
11 #include "sched.h"
12 #include "fd.h"
13 #include "error.h"
14 #include "stdout.h"
15 #include "buffer_tree.h"
16
17 /* Add STDOUT_FILENO to the write fd set if there is input data available. */
18 static void stdout_pre_select(struct sched *s, void *context)
19 {
20         struct stdout_task *sot = context;
21         int ret;
22
23         ret = btr_node_status(sot->btrn, 0, BTR_NT_LEAF);
24         if (ret > 0)
25                 para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
26         else if (ret < 0)
27                 sched_min_delay(s);
28 }
29
30 /*
31  * This function writes input data from the buffer tree to stdout if
32  * STDOUT_FILENO is writable.
33  */
34 static int stdout_post_select(struct sched *s, void *context)
35 {
36         struct stdout_task *sot = context;
37         struct btr_node *btrn = sot->btrn;
38         int ret;
39         char *buf;
40         size_t sz;
41
42         ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
43         if (ret < 0)
44                 goto out;
45         if (ret == 0)
46                 return 0;
47         if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
48                 return 0;
49
50         if (sot->must_set_nonblock_flag) {
51                 ret = mark_fd_nonblocking(STDOUT_FILENO);
52                 if (ret < 0)
53                         goto out;
54                 sot->must_set_nonblock_flag = false;
55         }
56         for (;;) {
57                 sz = btr_next_buffer(btrn, &buf);
58                 if (sz == 0)
59                         break;
60                 ret = xwrite(STDOUT_FILENO, buf, sz);
61                 if (ret <= 0)
62                         break;
63                 btr_consume(btrn, ret);
64         }
65 out:
66         if (ret < 0) {
67                 btr_remove_node(&sot->btrn);
68                 /* Revert to blocking mode if necessary. */
69                 fcntl(STDOUT_FILENO, F_SETFL, sot->fd_flags);
70         }
71         return ret;
72 }
73
74 /**
75  * Register a stdout task structure.
76  *
77  * \param sot The stdout task structure to register.
78  * \param s The task will be added to this scheduler's task list.
79  *
80  * This sets up \a sot and registers a task with \a sot as context pointer.
81  */
82 void stdout_task_register(struct stdout_task *sot, struct sched *s)
83 {
84         int ret;
85         struct task_info ti = {
86                 .pre_select = stdout_pre_select,
87                 .post_select = stdout_post_select,
88                 .context = sot,
89                 .name = "stdout",
90         };
91
92         /* See stdin.c for details. */
93         ret = fcntl(STDOUT_FILENO, F_GETFL);
94         if (ret < 0) {
95                 PARA_EMERG_LOG("F_GETFL: %s\n", strerror(errno));
96                 exit(EXIT_FAILURE);
97         }
98         sot->fd_flags = ret;
99         sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0;
100         sot->task = task_register(&ti, s);
101 }