+int read_line(int f, char *buf, int maxlen)
+{
+ eof_error = 0;
+
+ while (maxlen) {
+ buf[0] = 0;
+ read_buf(f, buf, 1);
+ if (buf[0] == 0) return 0;
+ if (buf[0] == '\n') {
+ buf[0] = 0;
+ break;
+ }
+ if (buf[0] != '\r') {
+ buf++;
+ maxlen--;
+ }
+ }
+ if (maxlen == 0) {
+ *buf = 0;
+ return 0;
+ }
+
+ eof_error = 1;
+
+ return 1;
+}
+
+
+void io_printf(int fd, const char *format, ...)
+{
+ va_list ap;
+ char buf[1024];
+ int len;
+
+ va_start(ap, format);
+ len = vslprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+
+ if (len < 0) exit_cleanup(RERR_STREAMIO);
+
+ write_sbuf(fd, buf);
+}
+
+
+/* setup for multiplexing an error stream with the data stream */
+void io_start_multiplex_out(int fd)
+{
+ multiplex_out_fd = fd;
+ io_flush();
+ io_start_buffering(fd);
+ io_multiplexing_out = 1;
+}
+
+/* setup for multiplexing an error stream with the data stream */
+void io_start_multiplex_in(int fd)
+{
+ multiplex_in_fd = fd;
+ io_flush();
+ io_multiplexing_in = 1;
+}
+
+/* write an message to the multiplexed error stream */
+int io_multiplex_write(enum logcode code, char *buf, int len)
+{
+ if (!io_multiplexing_out) return 0;
+
+ io_flush();
+ stats.total_written += (len+4);
+ mplex_write(multiplex_out_fd, code, buf, len);
+ return 1;
+}
+
+/* write a message to the special error fd */
+int io_error_write(int f, enum logcode code, char *buf, int len)
+{
+ if (f == -1) return 0;
+ mplex_write(f, code, buf, len);
+ return 1;
+}
+
+/* stop output multiplexing */
+void io_multiplexing_close(void)
+{
+ io_multiplexing_out = 0;
+}