From eeafd6cfe0a6f85520b6a0b92d658c0485d9794a Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Sat, 8 Dec 2012 00:00:00 -0600 Subject: [PATCH] top: highlight all regular search string(s) when found With the recent inspect search highlight provisions in place, the lack of highlighting in task based searches has grown from being only irritating to a real defect. Thus, this commit introduces parallel functionality to those searches initiated within a visible task window. And just as separate inspect searches are possible for each selection, per window task searches are provided. However, it should be noted that there are differences between task based searches and inspect type searches: * There is no concept of out-of-view data when dealing . with task rows -- if the data can't bee seen, it has . not, in fact, been constructed from a proc_t struct. * While inspect data is output at the character level, . up to now all task display data was only potentially . output and it was always based on a complete string. * With task search highlighting, rows now containing a . match must be output in pieces and, therefore, can't . be optimized away like other rows which haven't been . been altered. This is because top cannot predict the . the contents of a search string or, how many matches . might occur in a given row. Short search strings and . many matches would raise buffer needs geometrically. (now that we know a '.' + 2 spaces is squeezed to one) (everything's perfectly justified, but it's just luck) Signed-off-by: Jim Warner --- top/top.c | 73 +++++++++++++++++++++++++++++++++++++------------------ top/top.h | 19 ++++++++++++--- 2 files changed, 65 insertions(+), 27 deletions(-) diff --git a/top/top.c b/top/top.c index e7bbc558..082f7a51 100644 --- a/top/top.c +++ b/top/top.c @@ -1578,11 +1578,6 @@ static void build_headers (void) { #ifdef EQUCOLHDRYES // prepare to even out column header lengths... if (hdrmax + w->hdrcaplen < (x = strlen(w->columnhdr))) hdrmax = x - w->hdrcaplen; - // must sacrifice last header position to avoid task row abberations - w->eolcap = Caps_endline; -#else - if (Screen_cols > (int)strlen(w->columnhdr)) w->eolcap = Caps_endline; - else w->eolcap = Caps_off; #endif // with forest view mode, we'll need tgid, ppid & start_time... if (CHKw(w, Show_FOREST)) Frames_libflags |= (L_status | L_stat); @@ -2360,7 +2355,7 @@ struct I_ent { int farg; // 1 = '%d' in fmts, 0 = not (future use) const char *caps; // not really caps, show_special() delim's char *fstr; // entry's current/active search string - int flen; // the above's strlen, but no call overhead + int flen; // above's strlen, without call overhead }; struct I_struc { int demo; // do NOT save table entries in rcfile @@ -2377,9 +2372,6 @@ static size_t Insp_bufsz; // allocated size of Insp_buf static size_t Insp_bufrd; // bytes actually in Insp_buf static struct I_ent *Insp_sel; // currently selected Inspect entry - // The size of preallocated I_ent.fstr, same as linein() -#define INSP_FBSZ MEDBUFSIZ - // Our 'make status line' macro #define INSP_MKSL(big,txt) { int _sz = big ? Screen_cols : 80; \ putp(tg2(0, (Msg_row = 3))); \ @@ -2489,7 +2481,7 @@ static void insp_do_pipe (char *fmts, int pid) { * insp_find_str() - find the next Insp_sel->fstr match * insp_make_row() - highlight any Insp_sel->fstr matches in-view * If Insp_sel->fstr is found in the designated row, he returns the - * offest from the start of the row, otherwise he returns a huge + * offset from the start of the row, otherwise he returns a huge * integer so traditional fencepost usage can be employed. */ static inline int insp_find_ofs (int col, int row) { #define begFS (int)(fnd - Insp_p[row]) @@ -2529,7 +2521,7 @@ static void insp_find_str (int ch, int *col, int *row) { return; } if (ch == 'L' || ch == '/') { - snprintf(Insp_sel->fstr, INSP_FBSZ, "%s", linein(N_txt(GET_find_str_txt))); + snprintf(Insp_sel->fstr, FNDBUFSIZ, "%s", linein(N_txt(GET_find_str_txt))); Insp_sel->flen = strlen(Insp_sel->fstr); found = 0; } @@ -3101,7 +3093,7 @@ try_inspect_entries: } iT(farg) = (strstr(iT(fmts), "%d")) ? 1 : 0; - iT(fstr) = alloc_c(INSP_FBSZ); + iT(fstr) = alloc_c(FNDBUFSIZ); iT(flen) = 0; if (Rc_questions < 0) Rc_questions = 1; @@ -3120,7 +3112,7 @@ try_inspect_entries: Inspect.tab[i].name = strdup(sels[i]); Inspect.tab[i].func = insp_do_demo; Inspect.tab[i].fmts = strdup(N_txt(YINSP_deqkey_txt)); - Inspect.tab[i].fstr = alloc_c(INSP_FBSZ); + Inspect.tab[i].fstr = alloc_c(FNDBUFSIZ); } #undef mkS } @@ -3585,6 +3577,8 @@ static void wins_stage_2 (void) { for (i = 0; i < GROUPSMAX; i++) { win_names(&Winstk[i], Winstk[i].rc.winname); capsmk(&Winstk[i]); + Winstk[i].findstr = alloc_c(FNDBUFSIZ); + Winstk[i].findlen = 0; } if (Batch) OFFw(Curwin, View_SCROLL); @@ -3640,6 +3634,21 @@ static void file_writerc (void) { } // end: file_writerc + /* + * This guy is a *Helper* function serving the following two masters: + * find_string() - find the next match in a given window + * task_show() - highlight all matches currently in-view + * If q->findstr is found in the designated buffer, he returns the + * offset from the start of the buffer, otherwise he returns -1. */ +static inline int find_ofs (const WIN_t *q, const char *buf) { + char *fnd; + + if (q->findstr[0] && (fnd = STRSTR(buf, q->findstr))) + return (int)(fnd - buf); + return -1; +} // end: find_ofs + + /* This is currently the one true prototype require by top. It is placed here, instead of top.h, so as to avoid a compiler @@ -3648,29 +3657,29 @@ static const char *task_show (const WIN_t *q, const proc_t *p); static void find_string (int ch) { #define reDUX (found) ? N_txt(WORD_another_txt) : "" - static char str[SCREENMAX]; static int found; int i; - if ('&' == ch && !str[0]) { + if ('&' == ch && !Curwin->findstr[0]) { show_msg(N_txt(FIND_no_next_txt)); return; } if ('L' == ch) { - strcpy(str, linein(N_txt(GET_find_str_txt))); + snprintf(Curwin->findstr, FNDBUFSIZ, "%s", linein(N_txt(GET_find_str_txt))); + Curwin->findlen = strlen(Curwin->findstr); found = 0; } - if (str[0]) { + if (Curwin->findstr[0]) { SETw(Curwin, INFINDS_xxx); for (i = Curwin->begtask; i < Frame_maxtask; i++) { - if (STRSTR(task_show(Curwin, Curwin->ppt[i]), str)) { + if (-1 < find_ofs(Curwin, task_show(Curwin, Curwin->ppt[i]))) { found = 1; if (i == Curwin->begtask) continue; Curwin->begtask = i; return; } } - show_msg(fmtmk(N_fmt(FIND_no_find_fmt), reDUX, str)); + show_msg(fmtmk(N_fmt(FIND_no_find_fmt), reDUX, Curwin->findstr)); } #undef reDUX } // end: find_string @@ -4654,10 +4663,26 @@ static const char *task_show (const WIN_t *q, const proc_t *p) { } // end: for 'maxpflgs' if (!CHKw(q, INFINDS_xxx)) { - PUFF("\n%s%s%s", (CHKw(q, Show_HIROWS) && 'R' == p->state) - ? q->capclr_rowhigh : q->capclr_rownorm - , rbuf - , q->eolcap); + const char *cap = ((CHKw(q, Show_HIROWS) && 'R' == p->state)) + ? q->capclr_rowhigh : q->capclr_rownorm; + char *row = rbuf; + int ofs; + /* since we can't predict what the search string will be and, + considering what a single space search request would do to + potential buffer needs, when any matches are found we skip + normal output routing and send all of the results directly + to the terminal (and we sound asthmatic: poof, putt, puff) */ + if (-1 < (ofs = find_ofs(q, row))) { + POOF("\n", cap); + do { + row[ofs] = '\0'; + PUTT("%s%s%s%s", row, q->capclr_hdr, q->findstr, cap); + row += (ofs + q->findlen); + ofs = find_ofs(q, row); + } while (-1 < ofs); + PUTT("%s%s", row, Caps_endline); + } else + PUFF("\n%s%s%s", cap, row, Caps_endline); } return rbuf; #undef makeVAR @@ -4677,7 +4702,7 @@ static int window_show (WIN_t *q, int wmax) { int i, lwin; // Display Column Headings -- and distract 'em while we sort (maybe) - PUFF("\n%s%s%s", q->capclr_hdr, q->columnhdr, q->eolcap); + PUFF("\n%s%s%s", q->capclr_hdr, q->columnhdr, Caps_endline); if (CHKw(q, Show_FOREST)) forest_create(q); diff --git a/top/top.h b/top/top.h index 4547403c..7f8e96f0 100644 --- a/top/top.h +++ b/top/top.h @@ -125,6 +125,9 @@ char *strcasestr(const char *haystack, const char *needle); #define ROWMAXSIZ ( SCREENMAX + 16 * (CAPBUFSIZ + CLRBUFSIZ) ) // minimum size guarantee for dynamically acquired 'readfile' buffer #define READMINSZ 2048 + // size of preallocated search string buffers, same as linein() +#define FNDBUFSIZ MEDBUFSIZ + // space between task fields/columns #define COLPADSTR " " @@ -370,8 +373,9 @@ typedef struct WIN_t { #else columnhdr [SCREENMAX], // column headings for procflgs #endif - *eolcap, // window specific eol termcap *captab [CAPTABMAX]; // captab needed by show_special() + char *findstr; // window's current/active search string + int findlen; // above's strlen, without call overhead proc_t **ppt; // this window's proc_t ptr array struct WIN_t *next, // next window in window stack *prev; // prior window in window stack @@ -464,8 +468,8 @@ typedef struct WIN_t { return Frame_srtflg * strverscmp((*Q)->s, (*P)->s); } /* - * The following two macros are used to 'inline' those portions of the - * display process requiring formatting, while protecting against any + * The following three macros are used to 'inline' those portions of the + * display process involved in formatting, while protecting against any * potential embedded 'millesecond delay' escape sequences. */ /** PUTT - Put to Tty (used in many places) @@ -497,6 +501,14 @@ typedef struct WIN_t { putp(_ptr); } } \ } while (0) + /** POOF - Pulled Out of Frame (used in only 1 place) + . for output that is/was sent directly to the terminal + but would otherwise have been counted as a Pseudo_row */ +#define POOF(str,cap) do { \ + putp(str); putp(cap); \ + if (Pseudo_row + 1 < Screen_rows) ++Pseudo_row; \ + } while (0) + /* Orderly end, with any sort of message - see fmtmk */ #define debug_END(s) { \ static void error_exit (const char *); \ @@ -674,6 +686,7 @@ typedef struct WIN_t { //atic void wins_stage_2 (void); /*------ Interactive Input support (do_key helpers) --------------------*/ //atic void file_writerc (void); +//atic inline int find_ofs (const WIN_t *q, const char *buf); //atic void find_string (int ch); //atic void help_view (void); //atic void keys_global (int ch);