/* This actually is a hack. * * We only have one single operation active at a time. So we can use * a static buffer here which keeps the intermediate string. */ static const char * get_src(const char *name) { static TINO_BUF buf; if (!m_source) return name; tino_buf_resetO(&buf); tino_buf_add_sO(&buf, m_source); tino_buf_add_sO(&buf, name); return tino_buf_get_sN(&buf); }
/* This is plain crap, really, however there is no good support for * this all in my lib yet (there is no support for such things in * nearly no language, either. Python is best in this regard). */ static void dump_line(const char *ptr, size_t n, int lineend) { const char *p; start_line(0, lineend); p = tino_buf_get_sN(&prefix); if (flag_hexdump) tino_xd(&out, p, 8, byte_pos, (const unsigned char *)ptr, n+lineend); else { if (p && *p) tino_data_putsA(&out, p); #ifdef HAVE_ESCAPE_XML if (flag_xml) tino_data_write_xmlA(&out, ptr, n, flag_xml-1); else #endif #ifdef HAVE_ESCAPE_JSON if (flag_xml) tino_data_write_jsonA(&out, ptr, n); else #endif tino_data_writeA(&out, ptr, n); } byte_pos += n+lineend; in_line = !lineend; p = in_line ? line_cont_suffix : line_suffix; if (!p && !flag_hexdump) p = "\n"; if (p && *p) tino_data_putsA(&out, p); }
static void unbuffered(const char *arg0, int argc, char **argv) { TINO_BUF buf; if (!line_cont_suffix && !flag_hexdump) if (flag_localtime || flag_linecount || flag_utc || flag_verbose) line_cont_suffix = "\n"; producer = 0; if (argc) { int fds[2], redir[TINO_OPEN_MAX], fdmax, i; if (tino_file_pipeE(fds)) tino_exit("cannot create pipe"); fdmax = fd_in<3 ? 3 : fd_in+1; for (i=fdmax; --i>=0; ) redir[i] = -1; /* preserve all FDs */ if (fd_in<0) fd_in = 1; redir[2] = flag_both ? fds[1] : 2; /* catch stderr on -d, too */ if (fd_in==2) redir[1] = redir[2]; /* swap stdin/stderr on -i2 */ redir[fd_in] = fds[1]; /* catch the given FD */ /* catch the child's output for preprocessing */ producer = tino_fork_execO(redir, fdmax, argv, NULL, 0, NULL); tino_file_closeE(fds[1]); fd_in = fds[0]; #if 0 /* Following is a mess. It is only needed for a consumer, though. * With a producer we see EOF on the pipe. * Shall be handled implicitely by a library somehow: */ tino_sigset(SIGCHLD, terminate); terminate(); /* catch early terminated childs */ #endif } tino_buf_initO(&buf); if (producer && flag_verbose) { start_line(1, 1); add_prefix("start"); for (; *argv; argv++) add_prefix(" '%s'", *argv); /* XXX TODO sadly, escape is implemented in tino_io, not in tino_buf */ add_prefix("\n"); out_open(); tino_data_putsA(&out, tino_buf_get_sN(&prefix)); } if (fd_in<0) fd_in = 0; while (tino_buf_readE(&buf, fd_in, -1)) { size_t n; out_open(); /* XXX TODO MISSING: * for flag_buffer==1 or flag_buffer==2 * immediately write STDOUT(1), * but buffer STDERR(dump_line) */ while ((n=tino_buf_get_lenO(&buf))>0) { const char *ptr; size_t k, p; ptr = tino_buf_getN(&buf); p = 0; for (k=0; k<n; k++) if (ptr[k]==line_terminator) { dump_line(ptr+p, k-p, 1); p = k+1; } /* k=n */ if (flag_buffer && p) n = p; /* do not output incomplete line */ else if ((flag_buffer>1 && n<=99999) || flag_buffer>2) break; /* buffer fragments */ /* We shall, nonblockingly, read additional input data here, * if available. Leave this to future. */ TINO_XXX; if (p<n) dump_line(ptr+p, n-p, 0); if (flag_cat) tino_buf_advanceO(&buf, n); else if (tino_buf_write_away_allE(&buf, 1, n)) { /* silently drop out */ *tino_main_errflag = 1; break; } if (flag_buffer) break; } out_flush(); } { size_t n; /* in case of flag_buffer: send the rest */ if ((n=tino_buf_get_lenO(&buf))>0) { const char *ptr; out_open(); ptr = tino_buf_getN(&buf); dump_line(ptr, n, 0); if (!flag_cat && tino_buf_write_away_allE(&buf, 1, n)) *tino_main_errflag = 1; } } if (producer) { char *cause; #if 0 tino_sigdummy(SIGCHLD); /* prevent reentrance of waitpid() */ #endif /* wait for child to finish after the pipe was closed, * so give the child the chance to terminate. */ tino_file_closeE(0); *tino_main_errflag = tino_wait_child_exact(producer, &cause); if (flag_verbose) { start_line(1, 1); add_prefix("end %s\n", cause); out_open(); tino_data_putsA(&out, tino_buf_get_sN(&prefix)); } } out_close(); /* close(2) */ }