/// Implementation of the builtin count command, used to count the number of arguments sent to it. static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) { UNUSED(parser); int argc = 0; // Count the newlines coming in via stdin like `wc -l`. if (streams.stdin_is_directly_redirected) { char buf[COUNT_CHUNK_SIZE]; while (true) { long n = read_blocked(streams.stdin_fd, buf, COUNT_CHUNK_SIZE); // Ignore all errors for now. if (n <= 0) break; for (int i = 0; i < n; i++) { if (buf[i] == L'\n') { argc++; } } } } // Always add the size of argv. // That means if you call `something | count a b c`, you'll get the count of something _plus 3_. argc += builtin_count_args(argv) - 1; streams.out.append_format(L"%d\n", argc); return argc == 0 ? STATUS_CMD_ERROR : STATUS_CMD_OK; }
/// Read from descriptors until they are empty. /// /// \param j the job to test static void read_try(job_t *j) { io_buffer_t *buff = NULL; // Find the last buffer, which is the one we want to read from. const io_chain_t chain = j->all_io_redirections(); for (size_t idx = 0; idx < chain.size(); idx++) { io_data_t *d = chain.at(idx).get(); if (d->io_mode == IO_BUFFER) { buff = static_cast<io_buffer_t *>(d); } } if (buff) { debug(3, L"proc::read_try('%ls')", j->command_wcstr()); while (1) { char b[BUFFER_SIZE]; long l; l = read_blocked(buff->pipe_fd[0], b, BUFFER_SIZE); if (l == 0) { break; } else if (l < 0) { if (errno != EAGAIN) { debug(1, _(L"An error occured while reading output from code block")); wperror(L"read_try"); } break; } else { buff->out_buffer_append(b, l); } } } }
static const wchar_t *string_get_arg_stdin(wcstring *storage, const io_streams_t &streams) { std::string arg; for (;;) { char ch = '\0'; long rc = read_blocked(streams.stdin_fd, &ch, 1); if (rc < 0) { // failure return 0; } if (rc == 0) { // EOF if (arg.empty()) { return 0; } break; } if (ch == '\n') { break; } arg += ch; } *storage = str2wcstring(arg); return storage->c_str(); }
void io_buffer_t::read() { exec_close(pipe_fd[1]); if (io_mode == IO_BUFFER) { debug(4, L"io_buffer_t::read: blocking read on fd %d", pipe_fd[0]); while (1) { char b[4096]; long len = read_blocked(pipe_fd[0], b, 4096); if (len == 0) { break; } else if (len < 0) { // exec_read_io_buffer is only called on jobs that have exited, and will therefore // never block. But a broken pipe seems to cause some flags to reset, causing the // EOF flag to not be set. Therefore, EAGAIN is ignored and we exit anyway. if (errno != EAGAIN) { const wchar_t *fmt = _(L"An error occured while reading output from code block on fd %d"); debug(1, fmt, pipe_fd[0]); wperror(L"io_buffer_t::read"); } break; } else { buffer_.append(&b[0], &b[len]); } } } }
void io_buffer_t::read() { exec_close(pipe_fd[1]); if (io_mode == IO_BUFFER) { #if 0 if (fcntl( pipe_fd[0], F_SETFL, 0)) { wperror( L"fcntl" ); return; } #endif debug(4, L"io_buffer_t::read: blocking read on fd %d", pipe_fd[0]); while (1) { char b[4096]; long l; l = read_blocked(pipe_fd[0], b, 4096); if (l == 0) { break; } else if (l < 0) { // exec_read_io_buffer is only called on jobs that have exited, and will therefore // never block. But a broken pipe seems to cause some flags to reset, causing the // EOF flag to not be set. Therefore, EAGAIN is ignored and we exit anyway. if (errno != EAGAIN) { debug(1, _(L"An error occured while reading output from code block on file " L"descriptor %d"), pipe_fd[0]); wperror(L"io_buffer_t::read"); } break; } else { out_buffer_append(b, l); } } } }
/** Read from descriptors until they are empty. \param j the job to test */ static void read_try( job_t *j ) { io_data_t *d, *buff=0; /* Find the last buffer, which is the one we want to read from */ for( d = j->io; d; d=d->next ) { if( d->io_mode == IO_BUFFER ) { buff=d; } } if( buff ) { debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() ); while(1) { char b[BUFFER_SIZE]; int l; l=read_blocked( buff->param1.pipe_fd[0], b, BUFFER_SIZE ); if( l==0 ) { break; } else if( l<0 ) { if( errno != EAGAIN ) { debug( 1, _( L"An error occured while reading output from code block" ) ); wperror( L"read_try" ); } break; } else { buff->out_buffer_append(b, l); } } } }
/** Internal function used by input_common_readch to read one byte from fd 1. This function should only be called by input_common_readch(). */ static wint_t readb() { unsigned char arr[1]; int do_loop = 0; do { fd_set fd; int fd_max=1; int res; FD_ZERO( &fd ); FD_SET( 0, &fd ); if( env_universal_server.fd > 0 ) { FD_SET( env_universal_server.fd, &fd ); fd_max = env_universal_server.fd+1; } do_loop = 0; res = select( fd_max, &fd, 0, 0, 0 ); if( res==-1 ) { switch( errno ) { case EINTR: case EAGAIN: { if( interrupt_handler ) { int res = interrupt_handler(); if( res ) { return res; } if( lookahead_count ) { return lookahead_arr[--lookahead_count]; } } do_loop = 1; break; } default: { /* The terminal has been closed. Save and exit. */ return R_EOF; } } } else { if( env_universal_server.fd > 0 ) { if( FD_ISSET( env_universal_server.fd, &fd ) ) { debug( 3, L"Wake up on universal variable event" ); env_universal_read_all(); do_loop = 1; if( lookahead_count ) { return lookahead_arr[--lookahead_count]; } } } if( FD_ISSET( 0, &fd ) ) { if( read_blocked( 0, arr, 1 ) != 1 ) { /* The teminal has been closed. Save and exit. */ return R_EOF; } do_loop = 0; } } } while( do_loop ); return arr[0]; }
/// Internal function used by input_common_readch to read one byte from fd 0. This function should /// only be called by input_common_readch(). static char_event_t readb() { // do_loop must be set on every path through the loop; leaving it uninitialized allows the // static analyzer to assist in catching mistakes. unsigned char arr[1]; bool do_loop; do { // Flush callbacks. input_flush_callbacks(); fd_set fdset; int fd_max = 0; int ioport = iothread_port(); int res; FD_ZERO(&fdset); FD_SET(0, &fdset); if (ioport > 0) { FD_SET(ioport, &fdset); fd_max = std::max(fd_max, ioport); } // Get our uvar notifier. universal_notifier_t ¬ifier = universal_notifier_t::default_notifier(); // Get the notification fd (possibly none). int notifier_fd = notifier.notification_fd(); if (notifier_fd > 0) { FD_SET(notifier_fd, &fdset); fd_max = std::max(fd_max, notifier_fd); } // Get its suggested delay (possibly none). struct timeval tv = {}; const unsigned long usecs_delay = notifier.usec_delay_between_polls(); if (usecs_delay > 0) { unsigned long usecs_per_sec = 1000000; tv.tv_sec = (int)(usecs_delay / usecs_per_sec); tv.tv_usec = (int)(usecs_delay % usecs_per_sec); } res = select(fd_max + 1, &fdset, 0, 0, usecs_delay > 0 ? &tv : NULL); if (res == -1) { if (errno == EINTR || errno == EAGAIN) { if (interrupt_handler) { if (auto interrupt_evt = interrupt_handler()) { return *interrupt_evt; } else if (auto mc = lookahead_pop_evt()) { return *mc; } } do_loop = true; } else { // The terminal has been closed. return char_event_type_t::eof; } } else { // Assume we loop unless we see a character in stdin. do_loop = true; // Check to see if we want a universal variable barrier. bool barrier_from_poll = notifier.poll(); bool barrier_from_readability = false; if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset)) { barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd); } if (barrier_from_poll || barrier_from_readability) { env_universal_barrier(); } if (ioport > 0 && FD_ISSET(ioport, &fdset)) { iothread_service_completion(); if (auto mc = lookahead_pop_evt()) { return *mc; } } if (FD_ISSET(STDIN_FILENO, &fdset)) { if (read_blocked(0, arr, 1) != 1) { // The teminal has been closed. return char_event_type_t::eof; } // We read from stdin, so don't loop. do_loop = false; } } } while (do_loop); return arr[0]; }
/** Internal function used by input_common_readch to read one byte from fd 0. This function should only be called by input_common_readch(). */ static wint_t readb() { /* do_loop must be set on every path through the loop; leaving it uninitialized allows the static analyzer to assist in catching mistakes. */ unsigned char arr[1]; bool do_loop; do { /* Flush callbacks */ input_flush_callbacks(); fd_set fdset; int fd_max = 0; int ioport = iothread_port(); int res; FD_ZERO(&fdset); FD_SET(0, &fdset); if (ioport > 0) { FD_SET(ioport, &fdset); fd_max = maxi(fd_max, ioport); } /* Get our uvar notifier */ universal_notifier_t ¬ifier = universal_notifier_t::default_notifier(); /* Get the notification fd (possibly none) */ int notifier_fd = notifier.notification_fd(); if (notifier_fd > 0) { FD_SET(notifier_fd, &fdset); fd_max = maxi(fd_max, notifier_fd); } /* Get its suggested delay (possibly none) */ struct timeval tv = {}; const unsigned long usecs_delay = notifier.usec_delay_between_polls(); if (usecs_delay > 0) { unsigned long usecs_per_sec = 1000000; tv.tv_sec = (int)(usecs_delay / usecs_per_sec); tv.tv_usec = (int)(usecs_delay % usecs_per_sec); } res = select(fd_max + 1, &fdset, 0, 0, usecs_delay > 0 ? &tv : NULL); if (res==-1) { switch (errno) { case EINTR: case EAGAIN: { if (interrupt_handler) { int res = interrupt_handler(); if (res) { return res; } if (has_lookahead()) { return lookahead_pop(); } } do_loop = true; break; } default: { /* The terminal has been closed. Save and exit. */ return R_EOF; } } } else { /* Assume we loop unless we see a character in stdin */ do_loop = true; /* Check to see if we want a universal variable barrier */ bool barrier_from_poll = notifier.poll(); bool barrier_from_readability = false; if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset)) { barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd); } if (barrier_from_poll || barrier_from_readability) { env_universal_barrier(); } if (ioport > 0 && FD_ISSET(ioport, &fdset)) { iothread_service_completion(); if (has_lookahead()) { return lookahead_pop(); } } if (FD_ISSET(STDIN_FILENO, &fdset)) { if (read_blocked(0, arr, 1) != 1) { /* The teminal has been closed. Save and exit. */ return R_EOF; } /* We read from stdin, so don't loop */ do_loop = false; } } } while (do_loop); return arr[0]; }