/* dnd.c: Do Not Disturb - one-line output filter. Jason Hood, 6 October, 2010. Public Domain. Reads standard input, overwrites to standard output. Lines are truncated to fit the screen. The final line is kept if -k is given, otherwise it is removed. v1.01, 13 February, 2011: - fixed tab at screen edge; * blank the previous line before starting the next one. v1.02, 20 June, 2011: - Win32: another long line fix (pipe coming from DOS); * removed the DOS versions (not much point if you can't see it running). v1.03, 30 June, 2011: - lines before a blank line were not blanked out. v1.04, 9 January, 2012: - don't add any characters after a tab at screen edge; * just pass through if we've been redirected; * read a complete line before writing it; * Win32: use window width, not buffer width. v1.05, 31 August, 2013: - fix col when truncating at a tab. */ #define PVERS "1.05" #define PDATE "31 August, 2013" #include #include #include #ifdef _WIN32 #include // isatty #define WIN32_LEAN_AND_MEAN #include #else #include // isatty for UNIX? (djgpp at least) #endif #define TAB_SIZE 8 const char helpmsg[] = "\ Do Not Disturb by Jason Hood .\n\ Version " PVERS " (" PDATE "). Public Domain.\n\ http://misc.adoxa.vze.com/\n\ \n\ Read lines from standard input, overwrite each line (truncated to screen width)\n\ to standard output.\n\ \n\ ... | dnd [-k]\n\ \n\ -k - keep the last line\ "; int main( int argc, char* argv[] ) { int cols, col, len, wid; int ch; char buf[8192]; char* pos; #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; #else char* col_env; #endif if ((argc == 1 && isatty( 0 )) || (argc == 2 && (strcmp( argv[1], "/?" ) == 0 || strcmp( argv[1], "-?" ) == 0 || strcmp( argv[1], "--help" ) == 0))) { puts( helpmsg ); return 0; } if (argc == 2 && strcmp( argv[1], "--version" ) == 0) { puts( "Do Not Disturb version " PVERS " (" PDATE ")." ); return 0; } // If we've been redirected, just pass through. if (!isatty( 1 )) { for (;;) { len = read( 0, buf, sizeof(buf) ); if (len == 0) break; write( 1, buf, len ); } return 0; } // Stop just before the edge to prevent wrap (not disabling // ENABLE_WRAP_AT_EOL_OUTPUT in Windows because it doesn't seem to work when // piping from a DOS program, at least in XP). #ifdef _WIN32 GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi ); cols = csbi.srWindow.Right; #else col_env = getenv( "COLUMNS" ); cols = (col_env) ? atoi( col_env ) - 1 : 79; #endif col = len = wid = 0; pos = buf; for (;;) { ch = getchar(); if (ch == '\n' || ch == EOF) { if (ch == EOF && wid == 0) break; if (wid < len) { memset( pos, ' ', len - wid ); pos += len - wid; } *pos++ = '\r'; write( 1, buf, pos - buf ); len = wid; if (ch == EOF) break; col = wid = 0; pos = buf; } else if (ch == '\r') { col = 0; *pos++ = ch; } else if (ch == '\b') { if (col > 0) --col; *pos++ = ch; } else if (ch == '\a') { *pos++ = ch; } else if (col < cols) { if (ch == '\t') { int c = col + TAB_SIZE - (col % TAB_SIZE); if (c < cols) { col = c; *pos++ = ch; } } else { ++col; *pos++ = ch; } if (col > wid) wid = col; } if (pos == buf + sizeof(buf)) { write( 1, buf, sizeof(buf) ); pos = buf; } } if (argc == 1 || strcmp( argv[1], "-k" ) != 0) { if (len != 0) { memset( buf, ' ', len ); buf[len] = '\r'; write( 1, buf, len + 1 ); } } else { putchar( '\n' ); } return 0; }