1 #define _LARGEFILE64_SOURCE	/* required for GLIBC to enable stat64 and friends */
2 #include <ctype.h>
3 #include <sys/types.h>
4 #include <regex.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <pwd.h>
8 #include <errno.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 
12 #include "mt.h"
13 #include "error.h"
14 #include "my_pty.h"
15 #include "utils.h"
16 #include "term.h"
17 #include "help.h"
18 #include "mem.h"
19 #include "ui.h"
20 #include "misc.h"
21 #include "globals.h"
22 #include "clipboard.h"
23 
24 int scrollback_search_to_new_window(buffer *pbuf, char *org_title, char *find_str, mybool_t case_insensitive);
25 
find_string(buffer * pbuf,char * find,int offset,char direction,mybool_t case_insensitive)26 int find_string(buffer *pbuf, char *find, int offset, char direction, mybool_t case_insensitive)
27 {
28 	int loop, index = -1, rc;
29 	regex_t regex;
30 
31 	/* compile the searchstring (which can be a regular expression) */
32 	if ((rc = regcomp(&regex, find, REG_EXTENDED | (case_insensitive == MY_TRUE?REG_ICASE:0))))
33 	{
34 		regexp_error_popup(rc, &regex);
35 
36 		return -1;	/* failed -> not found */
37 	}
38 
39 	if (direction == 1)
40 	{
41 		for(loop=offset; loop<pbuf -> curpos; loop++)
42 		{
43 			if ((pbuf -> be)[loop].Bline == NULL)
44 				continue;
45 
46 			if (regexec(&regex, (pbuf -> be)[loop].Bline, 0, NULL, 0) == 0)
47 			{
48 				index = loop;
49 				break;
50 			}
51 		}
52 	}
53 	else if (direction == (char)-1)
54 	{
55 		for(loop=offset; loop>=0; loop--)
56 		{
57 			if ((pbuf -> be)[loop].Bline == NULL)
58 				continue;
59 
60 			if (regexec(&regex, (pbuf -> be)[loop].Bline, 0, NULL, 0) == 0)
61 			{
62 				index = loop;
63 				break;
64 			}
65 		}
66 	}
67 
68 	regfree(&regex);
69 
70 	return index;
71 }
72 
scrollback_find_popup(char ** find_str,mybool_t * pcase_insensitive)73 void scrollback_find_popup(char **find_str, mybool_t *pcase_insensitive)
74 {
75 	char *dummy;
76 	NEWWIN *mywin = create_popup(5, 40);
77 
78 	win_header(mywin, "Find");
79 
80 	dummy = edit_string(mywin, 3, 2, 40, 80, 0, reuse_searchstring?*find_str:NULL, HELP_SCROLLBACK_EDIT_SEARCH_STRING, -1, &search_h, pcase_insensitive);
81 	myfree(*find_str);
82 	*find_str = dummy;
83 
84 	delete_popup(mywin);
85 }
86 
scrollback_savefile(buffer * pbuf)87 void scrollback_savefile(buffer *pbuf)
88 {
89 	char *file = NULL;
90 	NEWWIN *mywin = create_popup(8, 40);
91 
92 	win_header(mywin, "Save buffer to file");
93 
94 	mvwprintw(mywin -> win, 4, 2, "Select file");
95 	file = edit_string(mywin, 5, 2, 40, find_path_max(), 0, NULL, HELP_SCROLLBACK_SAVEFILE_ENTER_FILENAME, -1, &cmdfile_h, NULL);
96 	if (file)
97 	{
98 		FILE *fh = fopen(file, "w");
99 		if (fh)
100 		{
101 			int loop;
102 
103 			for(loop=0; loop<pbuf -> curpos; loop++)
104 			{
105 				if ((pbuf -> be)[loop].Bline)
106 				{
107 					char display = 1;
108 					char *error;
109 					int dummy = -1;
110 					regmatch_t *pmatch = NULL;
111 
112 					/* check filter */
113 					if (!IS_MARKERLINE((pbuf -> be)[loop].pi))
114 					{
115 						(void)check_filter((pbuf -> be)[loop].pi, (pbuf -> be)[loop].Bline, &pmatch, &error, &dummy, 0, &display);
116 						if (error)
117 						{
118 							fprintf(fh, "%s\n", error);
119 							myfree(error);
120 						}
121 					}
122 					if (display)
123 					{
124 						fprintf(fh, "%s\n", USE_IF_SET((pbuf -> be)[loop].Bline, ""));
125 					}
126 
127 					if (pmatch) myfree(pmatch);
128 				}
129 			}
130 
131 			fclose(fh);
132 		}
133 		else
134 		{
135 			error_popup("Save scrollback buffer", -1, "Cannot write to file, reason: %s", strerror(errno));
136 		}
137 	}
138 
139 	delete_popup(mywin);
140 }
141 
get_lines_needed(char * string,int terminal_width)142 int get_lines_needed(char *string, int terminal_width)
143 {
144 	if (string)
145 		return (strlen(string) + terminal_width - 1) / terminal_width;
146 	else
147 		return 1;
148 }
149 
scrollback_displayline(int window_nr,NEWWIN * win,buffer * pbuf,int buffer_offset,int terminal_offset,int offset_in_line,mybool_t force_to_winwidth,char show_winnr)150 void scrollback_displayline(int window_nr, NEWWIN *win, buffer *pbuf, int buffer_offset, int terminal_offset, int offset_in_line, mybool_t force_to_winwidth, char show_winnr)
151 {
152 	char *cur_line = (pbuf -> be)[buffer_offset].Bline;
153 
154 	wmove(win -> win, terminal_offset, 0);
155 
156 	if (cur_line)
157 	{
158 		proginfo *cur_line_meta = (pbuf -> be)[buffer_offset].pi;
159 		double ts = (pbuf -> be)[buffer_offset].ts;
160 		char old_color_settings = 0;
161 
162 		if (scrollback_no_colors && cur_line_meta != NULL)
163 		{
164 			old_color_settings = cur_line_meta -> cdef.colorize;
165 			cur_line_meta -> cdef.colorize = 0;
166 		}
167 		if (IS_MARKERLINE(cur_line_meta))
168 		{
169 			color_print(window_nr, win, cur_line_meta, cur_line, NULL, -1, MY_FALSE, 0, 0, ts, show_winnr);
170 		}
171 		else /* just a buffered line */
172 		{
173 			char *error = NULL;
174 			regmatch_t *pmatch = NULL;
175 			int matching_regex = -1;
176 			char display;
177 			(void)check_filter(cur_line_meta, cur_line, &pmatch, &error, &matching_regex, 0, &display);
178 			if (error)
179 			{
180 				color_print(window_nr, win, cur_line_meta, error, NULL, -1, MY_FALSE, 0, 0, ts, show_winnr);
181 				myfree(error);
182 			}
183 			if (display)
184 			{
185 				if (offset_in_line)
186 				{
187 					int line_len = strlen(cur_line);
188 					int new_size = 0;
189 
190 					if (offset_in_line < line_len)
191 						new_size = min(win -> width, line_len - offset_in_line);
192 
193 					color_print(window_nr, win, cur_line_meta, cur_line, pmatch, matching_regex, force_to_winwidth, offset_in_line, offset_in_line + new_size, ts, show_winnr);
194 				}
195 				else
196 				{
197 					color_print(window_nr, win, cur_line_meta, cur_line, pmatch, matching_regex, force_to_winwidth, 0, 0, ts, show_winnr);
198 				}
199 			}
200 
201 			myfree(pmatch);
202 		}
203 		if (scrollback_no_colors && cur_line_meta != NULL)
204 		{
205 			cur_line_meta -> cdef.colorize = old_color_settings;
206 		}
207 	}
208 	else /* an empty line */
209 	{
210 		/* do nothing */
211 	}
212 }
213 
214 
compute_text_dimensions(int * nlines,int * ncols,char fullscreen)215 void compute_text_dimensions(int *nlines, int *ncols, char fullscreen)
216 {
217 	if (fullscreen)
218 	{
219 		*nlines = max_y;
220 		*ncols = max_x;
221 	}
222 	else
223 	{
224 		*nlines = max_y - 6;
225 		*ncols = max_x - 6;
226 	}
227 }
228 
create_scrollback_windows(NEWWIN ** mywin1,NEWWIN ** mywin2,int nlines,int ncols,char fullscreen)229 void create_scrollback_windows(NEWWIN **mywin1, NEWWIN **mywin2, int nlines, int ncols, char fullscreen)
230 {
231 	/* Delete existing windows, if any. */
232 	if (*mywin1)
233 	{
234 		delete_popup(*mywin1);
235 	}
236 
237 	if (*mywin2)
238 	{
239 		delete_popup(*mywin2);
240 	}
241 
242 	/* Re-create windows, according to fullscreen flag */
243 	if (fullscreen)
244 	{
245 		*mywin1 = NULL;
246 		*mywin2 = create_popup(max_y, max_x);
247 		scrollok((*mywin2) -> win, FALSE); /* supposed to always return OK, according to the manpage */
248 
249 	}
250 	else
251 	{
252 		*mywin1 = create_popup(max_y - 4, max_x - 4);
253 		*mywin2 = create_popup(nlines, ncols);
254 		scrollok((*mywin2) -> win, FALSE); /* supposed to always return OK, according to the manpage */
255 	}
256 }
257 
scrollback_do(int window_nr,buffer * pbuf,int * winnrs,char * header)258 int scrollback_do(int window_nr, buffer *pbuf, int *winnrs, char *header)
259 {
260 	int rc = 0;
261 	char *find = NULL;
262 	char fullscreen = scrollback_fullscreen_default;
263 	NEWWIN *mywin1 = NULL, *mywin2 = NULL;
264 
265 	int nlines, ncols;
266 	compute_text_dimensions(&nlines, &ncols, fullscreen);
267 
268 	int offset = max(0, pbuf -> curpos - nlines); /* FIXME: aantal regels laten afhangen van lengte */
269 	char redraw = 2;
270 	int line_offset = 0;
271 	char show_winnr = default_sb_showwinnr;
272 	mybool_t case_insensitive = re_case_insensitive;
273 	buffer cur_lb;
274 	int loop = 0;
275 
276 	memset(&cur_lb, 0x00, sizeof(cur_lb));
277 
278 	for(loop=0; loop<pbuf -> curpos; loop++)
279 	{
280 		if ((pbuf -> be)[loop].Bline == NULL)
281 			continue;
282 
283 		cur_lb.be = myrealloc(cur_lb.be, (cur_lb.curpos + 1) * sizeof(buffered_entry));
284 		cur_lb.be[cur_lb.curpos].pi    = (pbuf -> be)[loop].pi;
285 		if ((pbuf -> be)[loop].pi != NULL && (!IS_MARKERLINE((pbuf -> be)[loop].pi)) && (pbuf -> be)[loop].pi -> cdef.term_emul != TERM_IGNORE)
286 		{
287 			color_offset_in_line *cmatches;
288 			int n_cmatches;
289 			cur_lb.be[cur_lb.curpos].Bline = emulate_terminal((pbuf -> be)[loop].Bline, &cmatches, &n_cmatches);
290 			myfree(cmatches);
291 		}
292 		else
293 			cur_lb.be[cur_lb.curpos].Bline = strdup((pbuf -> be)[loop].Bline);
294 		cur_lb.be[cur_lb.curpos].ts    = (pbuf -> be)[loop].ts;
295 		cur_lb.curpos++;
296 	}
297 
298 	LOG("---\n");
299 	if (global_highlight_str)
300 	{
301 		find = mystrdup(global_highlight_str);
302 	}
303 
304 	create_scrollback_windows(&mywin1, &mywin2, nlines, ncols, fullscreen);
305 
306 	for(;;)
307 	{
308 		int c, uc;
309 
310 		if (redraw == 2)
311 		{
312 			int index = 0;
313 			int lines_used = 0;
314 
315 			if (mywin1)
316 			{
317 				ui_inverse_on(mywin1);
318 				mvwprintw(mywin1 -> win, nlines + 1, 1, "%s - %d buffered lines", shorten_filename(header, max(24, ncols - 24)), cur_lb.curpos);
319 				ui_inverse_off(mywin1);
320 
321 				if (!no_linewrap) ui_inverse_on(mywin1);
322 				mvwprintw(mywin1 -> win, nlines + 1, ncols - 8, "LINEWRAP");
323 				if (!no_linewrap) ui_inverse_off(mywin1);
324 			}
325 
326 			werase(mywin2 -> win);
327 
328 			if (!no_linewrap && line_offset > 0)
329 			{
330 				int temp_line_offset = line_offset;
331 				int n_chars_to_display_left = strlen((cur_lb.be)[offset].Bline) - temp_line_offset;
332 
333 				while(lines_used < nlines && n_chars_to_display_left > 0)
334 				{
335 					scrollback_displayline(winnrs?winnrs[offset]:window_nr, mywin2, &cur_lb, offset, lines_used, temp_line_offset, 1, show_winnr);
336 
337 					temp_line_offset += ncols;
338 					n_chars_to_display_left -= ncols;
339 
340 					lines_used++;
341 				}
342 
343 				index++;
344 			}
345 
346 			for(;(offset + index) < cur_lb.curpos && lines_used < nlines;)
347 			{
348 				int lines_needed = get_lines_needed((cur_lb.be)[offset + index].Bline, ncols);
349 
350 				if (no_linewrap || lines_needed == 1)
351 				{
352 					scrollback_displayline(winnrs?winnrs[offset + index]:window_nr, mywin2, &cur_lb, offset + index, lines_used, no_linewrap?line_offset:0, no_linewrap, show_winnr);
353 					lines_used++;
354 				}
355 				else
356 				{
357 					int cur_line_offset = 0;
358 
359 					while(lines_used < nlines && lines_needed > 0)
360 					{
361 						scrollback_displayline(winnrs?winnrs[offset + index]:window_nr, mywin2, &cur_lb, offset + index, lines_used, cur_line_offset, 1, show_winnr);
362 						cur_line_offset += ncols;
363 						lines_used++;
364 						lines_needed--;
365 					}
366 				}
367 
368 				index++;
369 			}
370 
371 			redraw = 1;
372 		}
373 
374 		if (redraw == 1)
375 		{
376 			mydoupdate();
377 
378 			redraw = 0;
379 		}
380 
381 		c = wait_for_keypress(HELP_SCROLLBACK_HELP, 0, NULL, 1);
382 		uc = toupper(c);
383 
384 		if (c == 'q' || c == abort_key || c == KEY_CLOSE || c == KEY_EXIT)
385 		{
386 			break;
387 		}
388 		else if (c == 'Q' || c == -1)		/* Q: close whole stack of scrollbackwindows, -1: something got closed */
389 		{
390 			rc = -1;
391 			break;
392 		}
393 		else if (c == 20 && winnrs != NULL)	/* ^t */
394 		{
395 			show_winnr = 1 - show_winnr;
396 			redraw = 2;
397 		}
398 		else if (c == 'x')
399 		{
400 			send_to_clipboard(pbuf);
401 		}
402 		else if (c == 'Y')
403 		{
404 			no_linewrap = !no_linewrap;
405 			redraw = 2;
406 			line_offset = 0;
407 		}
408 		else if (c == KEY_F(9) || c == 23)	/* ^w */
409 		{
410 			fullscreen = ! fullscreen;
411 
412 			compute_text_dimensions(&nlines, &ncols, fullscreen);
413 
414 			create_scrollback_windows(&mywin1, &mywin2, nlines, ncols, fullscreen);
415 
416 			redraw = 2;
417 		}
418 		else if (c == 't')
419 		{
420 			statistics_menu();
421 		}
422 		else if ((c == KEY_LEFT || c == KEY_BACKSPACE) && no_linewrap)
423 		{
424 			if (line_offset > 0)
425 				line_offset--;
426 
427 			redraw = 2;
428 		}
429 		else if (c == KEY_SLEFT && no_linewrap)
430 		{
431 			if (line_offset >= (ncols / 2))
432 				line_offset -= (ncols / 2);
433 			else
434 				line_offset = 0;
435 
436 			redraw = 2;
437 		}
438 		else if (c == KEY_SRIGHT && no_linewrap)
439 		{
440 			line_offset += (ncols / 2);
441 
442 			redraw = 2;
443 		}
444 		else if (c == KEY_BEG && no_linewrap)
445 		{
446 			if (line_offset)
447 			{
448 				line_offset = 0;
449 				redraw = 2;
450 			}
451 		}
452 		else if (c == KEY_BTAB)
453 		{
454 			if (line_offset >= 4)
455 				line_offset -= 4;
456 			else
457 				line_offset = 0;
458 
459 			redraw = 2;
460 		}
461 		else if (c == KEY_RIGHT && no_linewrap)
462 		{
463 			line_offset++;
464 			redraw = 2;
465 		}
466 		else if ((c == KEY_UP ||
467 					c == 'y' ||
468 					c == 25  || /* ^y */
469 					c == 'k' ||
470 					/* c == 11  || */ /* ^k */
471 					c == 16)    /* ^p */
472 				&& (offset > 0 || (!no_linewrap && line_offset > 0)))
473 		{
474 			if (no_linewrap)
475 			{
476 				offset--;
477 			}
478 			else if (line_offset > 0)
479 			{
480 				line_offset = max(0, line_offset - ncols);
481 			}
482 			else
483 			{
484 				offset--;
485 
486 				line_offset = (get_lines_needed((cur_lb.be)[offset].Bline, ncols) - 1) * ncols;
487 			}
488 
489 			wmove(mywin2 -> win, 0, 0);
490 			winsdelln(mywin2 -> win, 1);
491 
492 			scrollback_displayline(winnrs?winnrs[offset]:window_nr, mywin2, &cur_lb, offset, 0, line_offset, no_linewrap, show_winnr);
493 
494 			redraw = 1;
495 		}
496 		else if ((c == KEY_DOWN ||
497 					c == 'e' ||
498 					c == 5   || /* ^e */
499 					c == 'j' ||
500 					c == 14  || /* ^n */
501 					c == 13  ||
502 					c == KEY_ENTER)
503 				&& offset < (cur_lb.curpos - 1))
504 		{
505 			if (no_linewrap)
506 			{
507 				offset++;
508 			}
509 			else if (strlen((cur_lb.be)[offset].Bline) > (line_offset + ncols))
510 			{
511 				line_offset += ncols;
512 			}
513 			else if (offset < (cur_lb.curpos - 1))
514 			{
515 				if (strlen((cur_lb.be)[offset].Bline) > (line_offset + ncols))
516 					line_offset += ncols;
517 				else
518 				{
519 					line_offset = 0;
520 					offset++;
521 				}
522 			}
523 
524 			redraw = 2;
525 		}
526 		else if ((c == KEY_NPAGE ||
527 					c == 'f' ||
528 					c == 6   || /* ^f */
529 					c == ('V' - 65 + 1) || /* ^v */
530 					c == ' ' ||
531 					c == 'z' ||
532 					c == 'u' ||
533 					c == ('U' - 65 + 1))   /* ^u */
534 				&& offset < (cur_lb.curpos - 1))
535 		{
536 			if (no_linewrap)
537 			{
538 				offset += nlines;
539 				if (offset >= cur_lb.curpos)
540 					offset = cur_lb.curpos - 1;
541 			}
542 			else
543 			{
544 				int n_lines_to_move = nlines;
545 
546 				while(n_lines_to_move > 0 && offset < (cur_lb.curpos))
547 				{
548 					if (line_offset > 0)
549 					{
550 						if (line_offset + ncols >= strlen((cur_lb.be)[offset].Bline))
551 						{
552 							line_offset = 0;
553 							offset++;
554 							n_lines_to_move--;
555 						}
556 						else
557 						{
558 							line_offset += ncols;
559 							n_lines_to_move--;
560 						}
561 					}
562 					else
563 					{
564 						n_lines_to_move -= get_lines_needed((cur_lb.be)[offset].Bline, ncols);
565 						offset++;
566 					}
567 				}
568 
569 				if (n_lines_to_move < 0)
570 					line_offset = (-n_lines_to_move) * ncols;
571 			}
572 
573 			redraw = 2;
574 		}
575 		else if ((c == KEY_PPAGE ||
576 					c == 'b' ||
577 					c == 2   ||     /* ^b */
578 					c == 'w' ||
579 					c == 'd' ||
580 					c == 4)         /* ^d */
581 				&& offset > 0)
582 		{
583 			if (no_linewrap)
584 			{
585 				offset -= nlines;
586 				if (offset < 0)
587 					offset = 0;
588 			}
589 			else
590 			{
591 				int n_lines_to_move = nlines;
592 
593 				if (line_offset)
594 					n_lines_to_move -= line_offset / ncols;
595 
596 				while(n_lines_to_move > 0 && offset > 0)
597 				{
598 					offset--;
599 
600 					n_lines_to_move -= get_lines_needed((cur_lb.be)[offset].Bline, ncols);
601 
602 					if (n_lines_to_move < 0)
603 					{
604 						line_offset = (get_lines_needed((cur_lb.be)[offset].Bline, ncols) + n_lines_to_move) * ncols;
605 					}
606 				}
607 			}
608 
609 			redraw = 2;
610 		}
611 		else if ((c == KEY_HOME ||
612 					c == 'g' ||
613 					c == '<' ||
614 					c == KEY_SBEG)
615 				&& offset > 0)
616 		{
617 			line_offset = offset = 0;
618 			redraw = 2;
619 		}
620 		else if ((c == KEY_END ||
621 					c == 'G' ||
622 					c == '>' ||
623 					c == KEY_SEND)
624 				&& offset < (cur_lb. curpos - 1))
625 		{
626 			offset = cur_lb. curpos - 1;
627 			redraw = 2;
628 		}
629 		else if (uc == 'R' || c == ('R' - 65 + 1) || c == ('L' - 65 + 1) || c == KEY_REFRESH)
630 		{
631 			redraw = 2;
632 		}
633 		else if (c == ('K' - 65 + 1) || c == KEY_MARK)
634 		{
635 			scrollback_find_popup(&find, &case_insensitive);
636 
637 			if (find)
638 			{
639 				int rc;
640 
641 				regfree(&global_highlight_re);
642 				myfree(global_highlight_str);
643 				global_highlight_str = NULL;
644 
645 				if ((rc = regcomp(&global_highlight_re, find, (case_insensitive == MY_TRUE?REG_ICASE:0) | REG_EXTENDED)))
646 				{
647 					regexp_error_popup(rc, &global_highlight_re);
648 					myfree(find);
649 				}
650 				else
651 				{
652 					global_highlight_str = find;
653 				}
654 
655 				redraw = 2; /* force redraw */
656 			}
657 
658 		}
659 		else if (c == 'f' || c == '/' || c == '?' || c == KEY_FIND || c == KEY_SFIND)
660 		{
661 			char direction = (c == '?' || c == KEY_SFIND) ? -1 : 1;
662 
663 			scrollback_find_popup(&find, &case_insensitive);
664 
665 			if (find)
666 			{
667 				if (scrollback_search_new_window)
668 				{
669 					if (scrollback_search_to_new_window(&cur_lb, header, find, case_insensitive) == -1)
670 					{
671 						/* cascaded close */
672 						rc = -1;
673 						break;
674 					}
675 				}
676 				else
677 				{
678 					int new_f_index;
679 
680 					redraw = 2; /* force redraw */
681 
682 					regfree(&global_highlight_re);
683 					myfree(global_highlight_str);
684 					global_highlight_str = NULL;
685 
686 					new_f_index = find_string(&cur_lb, find, 0, direction, case_insensitive);
687 					if (new_f_index == -1)
688 					{
689 						wrong_key();
690 					}
691 					else
692 					{
693 						offset = new_f_index;
694 						line_offset = 0;
695 					}
696 				}
697 			}
698 		}
699 		else if (uc == 'N' || c == KEY_NEXT || c == KEY_PREVIOUS || c == KEY_SNEXT)
700 		{
701 			if (find != NULL)
702 			{
703 				char direction = (c == 'n' || c == KEY_NEXT) ? 1 : -1;
704 				int start_offset = offset + direction;
705 				int new_f_index = find_string(&cur_lb, find, start_offset, direction, case_insensitive);
706 				if (new_f_index == -1)
707 				{
708 					wrong_key();
709 				}
710 				else
711 				{
712 					redraw = 2; /* force redraw */
713 					offset = new_f_index;
714 					line_offset = 0;
715 				}
716 			}
717 			else
718 			{
719 				wrong_key();
720 			}
721 		}
722 		else if (c == 's' || c == KEY_SAVE)
723 		{
724 			scrollback_savefile(&cur_lb);
725 			redraw = 2;	/* force redraw */
726 		}
727 		else if (c == 'h')
728 		{
729 			show_help(HELP_SCROLLBACK_HELP);
730 		}
731 		else if (c == 'c')
732 		{
733 			toggle_colors();
734 			redraw = 2;	/* force redraw */
735 		}
736 		else if (c == 'i')
737 		{
738 			info();
739 		}
740 		else if (c == 'T')
741 		{
742 			statistics_menu();
743 		}
744 		else if (c == 20)
745 		{
746 			toggle_subwindow_nr();
747 			redraw = 2;	/* force redraw */
748 		}
749 		else
750 		{
751 			wrong_key();
752 		}
753 	}
754 
755 	delete_popup(mywin2);
756 	if (mywin1)
757 		delete_popup(mywin1);
758 
759 	myfree(find);
760 
761 	delete_be_in_buffer(&cur_lb);
762 
763 	return rc;
764 }
765 
scrollback(void)766 void scrollback(void)
767 {
768 	int window = 0;
769 
770 	if (nfd > 1)
771 	{
772 		window = select_window(HELP_SCROLLBACK_SELECT_WINDOW, NULL);
773 	}
774 
775 	if (window != -1)
776 	{
777 		if (lb[window].bufferwhat == 0)
778 			error_popup("Scrollback", HELP_SCROLLBACK_NO_MARK, "Cannot scrollback: buffering is disabled.");
779 	}
780 
781 	if (window != -1 && lb[window].bufferwhat != 0)
782 	{
783 		int header_size = strlen(pi[window].filename) + 4;
784 		char *header = (char *)mymalloc(header_size + 1);
785 		snprintf(header, header_size, "%02d] %s", window, pi[window].filename);
786 		scrollback_do(window, &lb[window], NULL, header);
787 		myfree(header);
788 	}
789 }
790 
merged_scrollback_with_search(char * search_for,mybool_t case_insensitive)791 void merged_scrollback_with_search(char *search_for, mybool_t case_insensitive)
792 {
793 	int lc_size = nfd * sizeof(int);
794 	int *last_check = (int *)mymalloc(lc_size);
795 	int *winnr = NULL;
796 	buffer buf;
797 	regex_t reg;
798 	int rc;
799 
800 	memset(last_check, 0x00, lc_size);
801 	memset(&buf, 0x00, sizeof(buf));
802 
803 	/* compile the search string which is supposed to be a valid regular
804 	 * expression
805 	 */
806 	if (search_for)
807 	{
808 		if ((rc=regcomp(&reg, search_for, REG_EXTENDED | (case_insensitive == MY_TRUE?REG_ICASE:0))))
809 		{
810 			regexp_error_popup(rc, &reg);
811 			free(last_check);
812 			return;
813 		}
814 	}
815 
816 	/* merge all windows into one */
817 	for(;;)
818 	{
819 		int loop;
820 		double chosen_ts = (double)(((long long int)1) << 62);
821 		int chosen_win = -1;
822 		int curline;
823 		char *string;
824 		int checked_all = 0;
825 
826 		for(loop=0; loop<nfd; loop++)
827 		{
828 			if (lb[loop].curpos == last_check[loop])
829 			{
830 				checked_all++;
831 				continue;
832 			}
833 
834 			if (search_for != NULL && lb[loop].be[last_check[loop]].Bline != NULL)
835 			{
836 				rc = regexec(&reg, lb[loop].be[last_check[loop]].Bline, 0, NULL, 0);
837 
838 				/* did not match? don't add and continue */
839 				if (rc == REG_NOMATCH)
840 				{
841 					continue;
842 				}
843 
844 				/* is it an error? then popup and abort */
845 				if (rc != 0)
846 				{
847 					regexp_error_popup(rc, &reg);
848 					break;
849 				}
850 			}
851 
852 			if (lb[loop].be[last_check[loop]].ts <= chosen_ts)
853 			{
854 				chosen_ts = lb[loop].be[last_check[loop]].ts;
855 				chosen_win = loop;
856 			}
857 		}
858 
859 		if (chosen_win == -1)
860 		{
861 			if (checked_all == nfd)
862 				break;
863 
864 			for(loop=0; loop<nfd; loop++)
865 			{
866 				if (lb[loop].curpos > last_check[loop])
867 					last_check[loop]++;
868 			}
869 
870 			continue;
871 		}
872 
873 		if (!IS_MARKERLINE(lb[chosen_win].be[last_check[chosen_win]].pi))
874 		{
875 			/*** ADD LINE TO BUFFER ***/
876 			buf.be = (buffered_entry *)myrealloc(buf.be, sizeof(buffered_entry) * (buf.curpos + 1));
877 			winnr  = (int *)myrealloc(winnr, sizeof(int) * (buf.curpos + 1));
878 			curline = buf.curpos++;
879 			/* add the logline itself */
880 			string = lb[chosen_win].be[last_check[chosen_win]].Bline;
881 			if (string)
882 				buf.be[curline].Bline = mystrdup(string);
883 			else
884 				buf.be[curline].Bline = NULL;
885 			/* remember pointer to subwindow (required for setting colors etc.) */
886 			buf.be[curline].pi = lb[chosen_win].be[last_check[chosen_win]].pi;
887 			buf.be[curline].ts = lb[chosen_win].be[last_check[chosen_win]].ts;
888 			/* remember window nr. */
889 			winnr[curline] = chosen_win;
890 		}
891 
892 		last_check[chosen_win]++;
893 	}
894 
895 	if (buf.curpos == 0)
896 		error_popup("Search in all windows", -1, "Nothing found.");
897 	else
898 	{
899 		char *header;
900 
901 		if (search_for)
902 		{
903 			char *help = "Searched for: ";
904 			int len = strlen(help) + strlen(search_for) + 1;
905 			header = mymalloc(len);
906 			snprintf(header, len, "%s%s", help, search_for);
907 		}
908 		else
909 		{
910 			char *help = "Merge view";
911 			header = mymalloc(strlen(help) + 1);
912 			sprintf(header, "%s", help);
913 		}
914 
915 		scrollback_do(-1, &buf, winnr, header);
916 
917 		myfree(header);
918 	}
919 
920 	delete_be_in_buffer(&buf);
921 
922 	myfree(winnr);
923 
924 	myfree(last_check);
925 }
926 
scrollback_search_to_new_window(buffer * pbuf,char * org_title,char * find_str,mybool_t case_insensitive)927 int scrollback_search_to_new_window(buffer *pbuf, char *org_title, char *find_str, mybool_t case_insensitive)
928 {
929 	int loop, rc;
930 	regex_t regex;
931 	buffer cur_lb;
932 	char *new_header;
933 
934 	/* compile the searchstring (which can be a regular expression) */
935 	if ((rc = regcomp(&regex, find_str, REG_EXTENDED | (case_insensitive == MY_TRUE?REG_ICASE:0))))
936 	{
937 		regexp_error_popup(rc, &regex);
938 		return 0;
939 	}
940 
941 	memset(&cur_lb, 0x00, sizeof(buffer));
942 
943 	for(loop=0; loop<pbuf -> curpos; loop++)
944 	{
945 		if ((pbuf -> be)[loop].Bline == NULL)
946 			continue;
947 
948 		if (regexec(&regex, (pbuf -> be)[loop].Bline, 0, NULL, 0) == 0)
949 		{
950 			cur_lb.be = myrealloc(cur_lb.be, (cur_lb.curpos + 1) * sizeof(buffered_entry));
951 			cur_lb.be[cur_lb.curpos].Bline = (pbuf -> be)[loop].Bline;
952 			cur_lb.be[cur_lb.curpos].pi    = (pbuf -> be)[loop].pi;
953 			cur_lb.be[cur_lb.curpos].ts    = (pbuf -> be)[loop].ts;
954 			cur_lb.curpos++;
955 		}
956 	}
957 
958 	new_header = (char *)mymalloc(strlen(org_title) + 1 + strlen(find_str) + 1);
959 	sprintf(new_header, "%s %s", org_title, find_str);
960 
961 	rc = scrollback_do(-1, &cur_lb, NULL, new_header);
962 
963 	myfree(new_header);
964 
965 	myfree(cur_lb.be);
966 
967 	regfree(&regex);
968 
969 	return rc;
970 }
971