static int test_inchs(int level, char **argv, WINDOW *chrwin, WINDOW *strwin) { WINDOW *txtbox = 0; WINDOW *txtwin = 0; FILE *fp; int j; int txt_x = 0, txt_y = 0; int base_y; int limit; cchar_t ch; cchar_t text[MAX_COLS]; if (argv[level] == 0) { beep(); return FALSE; } if (level > 1) { txtbox = newwin(LINES - BASE_Y, COLS - level, BASE_Y, level); box(txtbox, 0, 0); wnoutrefresh(txtbox); txtwin = derwin(txtbox, getmaxy(txtbox) - 2, getmaxx(txtbox) - 2, 1, 1); base_y = 0; } else { txtwin = stdscr; base_y = BASE_Y; } keypad(txtwin, TRUE); /* enable keyboard mapping */ (void) cbreak(); /* take input chars one at a time, no wait for \n */ (void) noecho(); /* don't echo input */ txt_y = base_y; txt_x = 0; wmove(txtwin, txt_y, txt_x); if ((fp = fopen(argv[level], "r")) != 0) { while ((j = fgetc(fp)) != EOF) { if (waddch(txtwin, UChar(j)) != OK) { break; } } fclose(fp); } else { wprintw(txtwin, "Cannot open:\n%s", argv[1]); } while (!Quit(j = mvwgetch(txtwin, txt_y, txt_x))) { switch (j) { case KEY_DOWN: case 'j': if (txt_y < getmaxy(txtwin) - 1) txt_y++; else beep(); break; case KEY_UP: case 'k': if (txt_y > base_y) txt_y--; else beep(); break; case KEY_LEFT: case 'h': if (txt_x > 0) txt_x--; else beep(); break; case KEY_RIGHT: case 'l': if (txt_x < getmaxx(txtwin) - 1) txt_x++; else beep(); break; case 'w': test_inchs(level + 1, argv, chrwin, strwin); if (txtbox != 0) { touchwin(txtbox); wnoutrefresh(txtbox); } else { touchwin(txtwin); wnoutrefresh(txtwin); } break; default: beep(); break; } MvWPrintw(chrwin, 0, 0, "char:"); wclrtoeol(chrwin); if (txtwin != stdscr) { wmove(txtwin, txt_y, txt_x); if (win_wch(txtwin, &ch) != ERR) { if (wadd_wch(chrwin, &ch) != ERR) { for (j = txt_x + 1; j < getmaxx(txtwin); ++j) { if (mvwin_wch(txtwin, txt_y, j, &ch) != ERR) { if (wadd_wch(chrwin, &ch) == ERR) { break; } } else { break; } } } } } else { move(txt_y, txt_x); if (in_wch(&ch) != ERR) { if (wadd_wch(chrwin, &ch) != ERR) { for (j = txt_x + 1; j < getmaxx(txtwin); ++j) { if (mvin_wch(txt_y, j, &ch) != ERR) { if (wadd_wch(chrwin, &ch) == ERR) { break; } } else { break; } } } } } wnoutrefresh(chrwin); MvWPrintw(strwin, 0, 0, "text:"); wclrtobot(strwin); limit = getmaxx(strwin) - 5; if (txtwin != stdscr) { wmove(txtwin, txt_y, txt_x); if (win_wchstr(txtwin, text) != ERR) { (void) mvwadd_wchstr(strwin, 0, 5, text); } wmove(txtwin, txt_y, txt_x); if (win_wchnstr(txtwin, text, limit) != ERR) { (void) mvwadd_wchstr(strwin, 1, 5, text); } if (mvwin_wchstr(txtwin, txt_y, txt_x, text) != ERR) { (void) mvwadd_wchstr(strwin, 2, 5, text); } if (mvwin_wchnstr(txtwin, txt_y, txt_x, text, limit) != ERR) { (void) mvwadd_wchstr(strwin, 3, 5, text); } } else { move(txt_y, txt_x); if (in_wchstr(text) != ERR) { (void) mvwadd_wchstr(strwin, 0, 5, text); } move(txt_y, txt_x); if (in_wchnstr(text, limit) != ERR) { (void) mvwadd_wchstr(strwin, 1, 5, text); } if (mvin_wchstr(txt_y, txt_x, text) != ERR) { (void) mvwadd_wchstr(strwin, 2, 5, text); } if (mvin_wchnstr(txt_y, txt_x, text, limit) != ERR) { (void) mvwadd_wchstr(strwin, 3, 5, text); } } wnoutrefresh(strwin); } if (level > 1) { delwin(txtwin); delwin(txtbox); } return TRUE; }
int main(int argc, char *argv[]) { int optc; int option_differences = 0, option_differences_cumulative = 0, option_help = 0, option_version = 0; double interval = 2; char *command; int command_length = 0; /* not including final \0 */ setlocale(LC_ALL, ""); progname = argv[0]; while ((optc = getopt_long(argc, argv, "+d::hn:vt", longopts, (int *) 0)) != EOF) { switch (optc) { case 'd': option_differences = 1; if (optarg) option_differences_cumulative = 1; break; case 'h': option_help = 1; break; case 't': show_title = 0; break; case 'n': { char *str; interval = strtod(optarg, &str); if (!*optarg || *str) do_usage(); if(interval < 0.1) interval = 0.1; if(interval > ~0u/1000000) interval = ~0u/1000000; } break; case 'v': option_version = 1; break; default: do_usage(); break; } } if (option_version) { fprintf(stderr, "%s\n", VERSION); if (!option_help) exit(0); } if (option_help) { fprintf(stderr, usage, progname); fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr); fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr); fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr); fputs(" -n, --interval=<seconds>\t\tseconds to wait between updates\n", stderr); fputs(" -v, --version\t\t\t\tprint the version number\n", stderr); fputs(" -t, --no-title\t\t\tturns off showing the header\n", stderr); exit(0); } if (optind >= argc) do_usage(); command = strdup(argv[optind++]); command_length = strlen(command); for (; optind < argc; optind++) { char *endp; int s = strlen(argv[optind]); command = realloc(command, command_length + s + 2); /* space and \0 */ endp = command + command_length; *endp = ' '; memcpy(endp + 1, argv[optind], s); command_length += 1 + s; /* space then string length */ command[command_length] = '\0'; } get_terminal_size(); /* Catch keyboard interrupts so we can put tty back in a sane state. */ signal(SIGINT, die); signal(SIGTERM, die); signal(SIGHUP, die); signal(SIGWINCH, winch_handler); /* Set up tty for curses use. */ curses_started = 1; initscr(); nonl(); noecho(); cbreak(); for (;;) { time_t t = time(NULL); char *ts = ctime(&t); int tsl = strlen(ts); char *header; FILE *p; int x, y; int oldeolseen = 1; mbstate_t mbs; if (screen_size_changed) { get_terminal_size(); resizeterm(height, width); clear(); /* redrawwin(stdscr); */ screen_size_changed = 0; first_screen = 1; } if (show_title) { // left justify interval and command, // right justify time, clipping all to fit window width asprintf(&header, "Every %.1fs: %.*s", interval, min(width - 1, command_length), command); mvaddstr(0, 0, header); if (strlen(header) > (size_t) (width - tsl - 1)) mvaddstr(0, width - tsl - 4, "... "); mvaddstr(0, width - tsl + 1, ts); free(header); } if (!(p = popen(command, "r"))) { perror("popen"); do_exit(2); } memset(&mbs, 0, sizeof(mbs)); for (y = show_title; y < height; y++) { int eolseen = 0, tabpending = 0; for (x = 0; x < width; x++) { wint_t c = L' '; int attr = 0, c_width; cchar_t cc; wchar_t wstr[2]; if (!eolseen) { /* if there is a tab pending, just spit spaces until the next stop instead of reading characters */ if (!tabpending) do c = readwc(p, &mbs); while (c != WEOF && !iswprint(c) && c != L'\n' && c != L'\t'); if (c == L'\n') if (!oldeolseen && x == 0) { x = -1; continue; } else eolseen = 1; else if (c == L'\t') tabpending = 1; if (c == WEOF || c == L'\n' || c == L'\t') c = L' '; if (tabpending && (((x + 1) % 8) == 0)) tabpending = 0; } wstr[0] = c; wstr[1] = 0; setcchar (&cc, wstr, 0, 0, NULL); move(y, x); if (option_differences) { cchar_t oldc; wchar_t oldwstr[2]; attr_t attrs; short colors; in_wch(&oldc); getcchar(&oldc, oldwstr, &attrs, &colors, NULL); attr = !first_screen && (wstr[0] != oldwstr[0] || (option_differences_cumulative && attrs)); } if (attr) standout(); add_wch(&cc); if (attr) standend(); c_width = wcwidth(c); if (c_width > 1) x += c_width - 1; } oldeolseen = eolseen; } pclose(p); first_screen = 0; refresh(); usleep(interval * 1000000); } endwin(); return 0; }
int main(int argc, char *argv[]) { int optc; int option_differences = 0, option_differences_cumulative = 0, option_exec = 0, option_beep = 0, option_color = 0, option_errexit = 0, option_help = 0, option_version = 0; double interval = 2; char *command; wchar_t *wcommand = NULL; char **command_argv; int command_length = 0; /* not including final \0 */ int wcommand_columns = 0; /* not including final \0 */ int wcommand_characters = 0; /* not including final \0 */ watch_usec_t next_loop; /* next loop time in us, used for precise time keeping only */ int pipefd[2]; int status; pid_t child; setlocale(LC_ALL, ""); progname = argv[0]; while ((optc = getopt_long(argc, argv, "+bced::hn:pvtx", longopts, (int *) 0)) != EOF) { switch (optc) { case 'b': option_beep = 1; break; case 'c': option_color = 1; break; case 'd': option_differences = 1; if (optarg) option_differences_cumulative = 1; break; case 'e': option_errexit = 1; break; case 'h': option_help = 1; break; case 't': show_title = 0; break; case 'x': option_exec = 1; break; case 'n': { char *str; interval = strtod(optarg, &str); if (!*optarg || *str) do_usage(); if(interval < 0.1) interval = 0.1; if(interval > ~0u/1000000) interval = ~0u/1000000; } break; case 'p': precise_timekeeping = 1; break; case 'v': option_version = 1; break; default: do_usage(); break; } } if (option_version) { fprintf(stderr, "%s\n", VERSION); if (!option_help) exit(0); } if (option_help) { fprintf(stderr, usage, progname); fputs(" -b, --beep\t\t\t\tbeep if the command has a non-zero exit\n", stderr); fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr); fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr); fputs(" -e, --errexit\t\t\t\texit watch if the command has a non-zero exit\n", stderr); fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr); fputs(" -n, --interval=<seconds>\t\tseconds to wait between updates\n", stderr); fputs(" -p, --precise\t\t\t\tprecise timing, ignore command run time\n", stderr); fputs(" -v, --version\t\t\t\tprint the version number\n", stderr); fputs(" -t, --no-title\t\t\tturns off showing the header\n", stderr); fputs(" -x, --exec\t\t\t\tpass command to exec instead of sh\n", stderr); exit(0); } if (optind >= argc) do_usage(); command_argv=&(argv[optind]); /* save for later */ command = strdup(argv[optind++]); command_length = strlen(command); for (; optind < argc; optind++) { char *endp; int s = strlen(argv[optind]); command = realloc(command, command_length + s + 2); /* space and \0 */ endp = command + command_length; *endp = ' '; memcpy(endp + 1, argv[optind], s); command_length += 1 + s; /* space then string length */ command[command_length] = '\0'; } // convert to wide for printing purposes //mbstowcs(NULL, NULL, 0); wcommand_characters = mbstowcs(NULL, command, 0); if(wcommand_characters < 0) { fprintf(stderr, "Unicode Handling Error\n"); exit(1); } wcommand = (wchar_t*)malloc((wcommand_characters+1) * sizeof(wcommand)); if(wcommand == NULL) { fprintf(stderr, "Unicode Handling Error (malloc)\n"); exit(1); } mbstowcs(wcommand, command, wcommand_characters+1); wcommand_columns = wcswidth(wcommand, -1); get_terminal_size(); /* Catch keyboard interrupts so we can put tty back in a sane state. */ signal(SIGINT, die); signal(SIGTERM, die); signal(SIGHUP, die); signal(SIGWINCH, winch_handler); /* Set up tty for curses use. */ curses_started = 1; initscr(); if (option_color) { if (has_colors()) { start_color(); use_default_colors(); init_ansi_colors(); } else option_color = 0; } nonl(); noecho(); cbreak(); if (precise_timekeeping) next_loop = get_time_usec(); for (;;) { time_t t = time(NULL); char *ts = ctime(&t); int tsl = strlen(ts); char *header; FILE *p; int x, y; int oldeolseen = 1; if (screen_size_changed) { get_terminal_size(); resizeterm(height, width); clear(); /* redrawwin(stdscr); */ screen_size_changed = 0; first_screen = 1; } if (show_title) { // left justify interval and command, // right justify time, clipping all to fit window width int hlen = asprintf(&header, "Every %.1fs: ", interval); // the rules: // width < tsl : print nothing // width < tsl + hlen + 1: print ts // width = tsl + hlen + 1: print header, ts // width < tsl + hlen + 4: print header, ..., ts // width < tsl + hlen + wcommand_columns: print header, truncated wcommand, ..., ts // width > "": print header, wcomand, ts // this is slightly different from how it used to be if(width >= tsl) { if(width >= tsl + hlen + 1) { mvaddstr(0, 0, header); if(width >= tsl + hlen + 2) { if(width < tsl + hlen + 4) { mvaddstr(0, width - tsl - 4, "... "); }else{ if(width < tsl + hlen + wcommand_columns) { // print truncated int avail_columns = width - tsl - hlen; int using_columns = wcommand_columns; int using_characters = wcommand_characters; while(using_columns > avail_columns - 4) { using_characters--; using_columns = wcswidth(wcommand, using_characters); } mvaddnwstr(0, hlen, wcommand, using_characters); mvaddstr(0, width - tsl - 4, "... "); }else{ mvaddwstr(0, hlen, wcommand); } } } } mvaddstr(0, width - tsl + 1, ts); } free(header); } /* allocate pipes */ if (pipe(pipefd)<0) { perror("pipe"); do_exit(7); } /* flush stdout and stderr, since we're about to do fd stuff */ fflush(stdout); fflush(stderr); /* fork to prepare to run command */ child=fork(); if (child<0) { /* fork error */ perror("fork"); do_exit(2); } else if (child==0) { /* in child */ close (pipefd[0]); /* child doesn't need read side of pipe */ close (1); /* prepare to replace stdout with pipe */ if (dup2 (pipefd[1], 1)<0) { /* replace stdout with write side of pipe */ perror("dup2"); exit(3); } dup2(1, 2); /* stderr should default to stdout */ if (option_exec) { /* pass command to exec instead of system */ if (execvp(command_argv[0], command_argv)==-1) { perror("exec"); exit(4); } } else { status=system(command); /* watch manpage promises sh quoting */ /* propagate command exit status as child exit status */ if (!WIFEXITED(status)) { /* child exits nonzero if command does */ exit(1); } else { exit(WEXITSTATUS(status)); } } } /* otherwise, we're in parent */ close(pipefd[1]); /* close write side of pipe */ if ((p=fdopen(pipefd[0], "r"))==NULL) { perror("fdopen"); do_exit(5); } for (y = show_title; y < height; y++) { int eolseen = 0, tabpending = 0; wint_t carry = WEOF; for (x = 0; x < width; x++) { wint_t c = L' '; int attr = 0; if (!eolseen) { /* if there is a tab pending, just spit spaces until the next stop instead of reading characters */ if (!tabpending) do { if(carry == WEOF) { c = my_getwc(p); }else{ c = carry; carry = WEOF; } }while (c != WEOF && !isprint(c) && c<128 && wcwidth(c) == 0 && c != L'\n' && c != L'\t' && (c != L'\033' || option_color != 1)); if (c == L'\033' && option_color == 1) { x--; process_ansi(p); continue; } if (c == L'\n') if (!oldeolseen && x == 0) { x = -1; continue; } else eolseen = 1; else if (c == L'\t') tabpending = 1; if (x==width-1 && wcwidth(c)==2) { y++; x = -1; //process this double-width carry = c; //character on the next line continue; //because it won't fit here } if (c == WEOF || c == L'\n' || c == L'\t') c = L' '; if (tabpending && (((x + 1) % 8) == 0)) tabpending = 0; } move(y, x); if (option_differences) { cchar_t oldc; in_wch(&oldc); attr = !first_screen && ((wchar_t)c != oldc.chars[0] || (option_differences_cumulative && (oldc.attr & A_ATTRIBUTES))); } if (attr) standout(); addnwstr((wchar_t*)&c,1); if (attr) standend(); if(wcwidth(c) == 0) { x--; } if(wcwidth(c) == 2) { x++; } } oldeolseen = eolseen; } fclose(p); /* harvest child process and get status, propagated from command */ if (waitpid(child, &status, 0)<0) { perror("waitpid"); do_exit(8); }; /* if child process exited in error, beep if option_beep is set */ if ((!WIFEXITED(status) || WEXITSTATUS(status))) { if (option_beep) beep(); if (option_errexit) do_exit(8); } first_screen = 0; refresh(); if (precise_timekeeping) { watch_usec_t cur_time = get_time_usec(); next_loop += USECS_PER_SEC*interval; if (cur_time < next_loop) usleep(next_loop - cur_time); } else usleep(interval * 1000000); } endwin(); return 0; }