1 /***************************************************************************
2  *  Pinfo is a ncurses based lynx style info documentation browser
3  *
4  *  Copyright (C) 1999  Przemek Borys <pborys@dione.ids.pl>
5  *  Copyright (C) 2005  Bas Zoetekouw <bas@debian.org>
6  *  Copyright 2005  Nathanael Nerode <neroden@gcc.gnu.org>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of version 2 of the GNU General Public License as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful, but
13  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20  *  USA
21  ***************************************************************************/
22 
23 
24 #include "common_includes.h"
25 
26 void info_add_highlights(unsigned pos, unsigned cursor, unsigned long lines, unsigned column, char **message);
27 
28 void
substitutestr(char * src,char * dest,char * from,char * to)29 substitutestr(char *src, char *dest, char *from, char *to)
30 	/*
31 	 * Utility for substituting strings in given string.
32 	 * Used for internationalization of info headers.
33 	 */
34 {
35 	char *start = strstr(src, from);
36 	char tmp;
37 	if (!start)
38 		strcpy(dest, src);
39 	else
40 	{
41 		tmp = *start;
42 		*start = 0;
43 		strcpy(dest, src);
44 		strcat(dest, to);
45 		*start = tmp;
46 		start += strlen(from);
47 		strcat(dest, start);
48 	}
49 }
50 
51 void
addtopline(char * type,int column)52 addtopline(char *type, int column)
53 {
54 	char *buf1 = xmalloc(strlen(type) + 50);
55 	char *buf2 = xmalloc(strlen(type) + 50);
56 	int buf2len;
57 	strcpy(buf1, type);
58 
59 	substitutestr(buf1, buf2, "File:", _("File:"));
60 	substitutestr(buf2, buf1, "Node:", _("Node:"));
61 	substitutestr(buf1, buf2, "Next:", _("Next:"));
62 	substitutestr(buf2, buf1, "Prev:", _("Prev:"));
63 	substitutestr(buf1, buf2, "Up:", _("Up:"));
64 	attrset(topline);
65 	mymvhline(0, 0, ' ', maxx);	/* pads line with spaces -- estetic */
66 	buf2len=strlen(buf2);
67 	if (buf2len)
68 		buf2[buf2len - 1] = '\0';
69 	if (buf2len>column)
70 		mvaddstr(0, 0, buf2+column);
71 	attrset(normal);
72 	xfree(buf1);
73 	xfree(buf2);
74 }
75 
76 void
showscreen(char ** message,unsigned long lines,unsigned long pos,long cursor,int column)77 showscreen(char **message, unsigned long lines, unsigned long pos, long cursor, int column)
78 {
79 #ifdef getmaxyx
80 	getmaxyx(stdscr, maxy, maxx);
81 #endif
82 #ifdef HAVE_BKGDSET
83 	bkgdset(' ' | normal);
84 #endif
85 	attrset(normal);
86 	for (unsigned long i = pos; (i < lines) && (i < pos + maxy - 2); i++)
87 	{
88 		int tmp;
89 
90 		if (!message[i]) continue;
91 		tmp = strlen(message[i]) - 1;
92 		message[i][tmp] = 0;
93 		if (tmp>column)
94 			mvaddstr(i + 1 - pos, 0, message[i]+column);
95 		else
96 			move(i + 1 - pos,0);
97 #ifdef HAVE_BKGDSET
98 		clrtoeol();
99 #else
100 		myclrtoeol();
101 #endif
102 		message[i][tmp] = '\n';
103 	}
104 	clrtobot();
105 #ifdef HAVE_BKGDSET
106 	bkgdset(0);
107 #endif
108 	attrset(bottomline);
109 	mymvhline(maxy - 1, 0, ' ', maxx);
110 	move(maxy - 1, 0);
111 	if ((pos < lines - 1) &&(lines > pos + maxy - 2))
112 		printw(_("Viewing line %d/%d, %d%%"), pos + maxy - 2, lines,((pos + maxy - 2) * 100) / lines);
113 	else
114 		printw(_("Viewing line %d/%d, 100%%"), lines, lines);
115 	info_add_highlights(pos, cursor, lines, column, message);
116 	attrset(normal);
117 	move(0, 0);
118 	refresh();
119 }
120 
121 /*
122  * prints a line, taking care for the horizontal scrolling.
123  *  if the string fits in the window, it is drawn. If not,
124  *  it is either cut, or completely omitted.
125  */
126 void
info_addstr(int y,int x,char * txt,int column,int txtlen)127 info_addstr(int y, int x, char *txt, int column, int txtlen)
128 {
129   int xmax, UNUSED(ymax);
130   getmaxyx(stdscr, ymax, xmax);
131   /* Use xmax and mvaddnstr to force clipping.
132    * Fairly blunt instrument, but the best I could come up with.
133    * Breaks in the presence of tabs; I don't see how to handle them. */
134 	if (x>column)
135 		mvaddnstr(y,x-column,txt, xmax-(x-column) );
136 	else if (x+txtlen>column)
137 		mvaddnstr(y,0,txt+(column-x), xmax );
138 #ifdef __DEBUG__
139   refresh();
140 #endif /* __DEBUG__ */
141 }
142 
143 void
info_add_highlights(unsigned pos,unsigned cursor,unsigned long lines,unsigned column,char ** message)144 info_add_highlights(unsigned pos, unsigned cursor, unsigned long lines, unsigned column, char **message)
145 {
146 	for (unsigned long i = 0; i < hyperobjectcount; i++)
147 	{
148 		if ((hyperobjects[i].line >= pos) &&
149 				(hyperobjects[i].line < pos +(maxy - 2)))
150 		{
151 			/* first part of if's sets the required attributes */
152 			if (hyperobjects[i].type < 2)		/* menu */
153 			{
154 				if (i == cursor)
155 					attrset(menuselected);
156 				else
157 					attrset(menu);
158 			}
159 			else if (hyperobjects[i].type < 4)	/* note */
160 			{
161 				if (i == cursor)
162 					attrset(noteselected);
163 				else
164 					attrset(note);
165 			}
166 			else if (hyperobjects[i].type < HIGHLIGHT)	/* url */
167 			{
168 				if (i == cursor)
169 					attrset(urlselected);
170 				else
171 					attrset(url);
172 			}
173 			else /* quoted text -- highlight it */
174 			{
175 				attrset(infohighlight);
176 			}
177 			/* now we start actual drawing */
178 			if (hyperobjects[i].file[0] == 0)
179 			{
180 				if (hyperobjects[i].breakpos == -1)
181 				{
182 					info_addstr(1 + hyperobjects[i].line - pos,
183 							hyperobjects[i].col,
184 							hyperobjects[i].node,
185 							column,
186 							hyperobjects[i].nodelen);
187 
188 				}
189 				else
190 				{
191 					int j;
192 					char tmp = hyperobjects[i].node[hyperobjects[i].breakpos];
193 					hyperobjects[i].node[hyperobjects[i].breakpos] = 0;
194 					info_addstr(1 + hyperobjects[i].line - pos,
195 							hyperobjects[i].col,
196 							hyperobjects[i].node,
197 							column,
198 							hyperobjects[i].breakpos);
199 					hyperobjects[i].node[hyperobjects[i].breakpos] = tmp;
200 					j = hyperobjects[i].breakpos;
201 					/* skip leading spaces after newline */
202 					while (hyperobjects[i].node[j] == ' ')
203 						j++;
204 					if (hyperobjects[i].line - pos + 3 < maxy)
205 						info_addstr(1 + hyperobjects[i].line - pos + 1,
206 								j - hyperobjects[i].breakpos,
207 								hyperobjects[i].node + j,
208 								column,
209 								hyperobjects[i].nodelen-j);
210 				}
211 			}
212 			else
213 			{
214 				if (hyperobjects[i].breakpos == -1)
215 				{
216 					char *buf=xmalloc(hyperobjects[i].filelen+hyperobjects[i].nodelen+3);
217 					snprintf(buf,hyperobjects[i].filelen+hyperobjects[i].nodelen+3,
218 							"(%s)%s",hyperobjects[i].file,hyperobjects[i].node);
219 					info_addstr(1 + hyperobjects[i].line - pos,
220 							hyperobjects[i].col,
221 							buf,
222 							column,
223 							hyperobjects[i].filelen+hyperobjects[i].nodelen+2);
224 					xfree(buf);
225 				}
226 				else
227 				{
228 					static char buf[1024];
229 					char tmp;
230 					int j;
231 					strcpy(buf, "(");
232 					strcat(buf, hyperobjects[i].file);
233 					strcat(buf, ")");
234 					strcat(buf, hyperobjects[i].node);
235 					tmp = buf[hyperobjects[i].breakpos];
236 					buf[hyperobjects[i].breakpos] = 0;
237 					info_addstr(1 + hyperobjects[i].line - pos,
238 							hyperobjects[i].col,
239 							buf,
240 							column,
241 							hyperobjects[i].breakpos+2);
242 					buf[hyperobjects[i].breakpos] = tmp;
243 					j = hyperobjects[i].breakpos;
244 					/* skip leading spaces after newline */
245 					while (buf[j] == ' ')
246 						j++;
247 					if (hyperobjects[i].line - pos + 3 < maxy)
248 						info_addstr(1 + hyperobjects[i].line - pos + 1,
249 								j - hyperobjects[i].breakpos,
250 								buf + j,
251 								column,
252 								hyperobjects[i].filelen+hyperobjects[i].nodelen+2-j);
253 				}
254 			}
255 			attrset(normal);
256 		}
257 	}
258 #ifndef ___DONT_USE_REGEXP_SEARCH___
259 	if ((h_regexp_num) ||(aftersearch))
260 	{
261 		regmatch_t pmatch[1];
262 		if (maxy<2) maxy=2;
263 		unsigned long maxpos = pos +(maxy - 2);
264 		int maxregexp;
265 		if (maxpos > lines)
266 		{
267 			maxpos = lines;
268 		}
269 
270 		maxregexp = aftersearch ? h_regexp_num + 1 : h_regexp_num;
271 		/*
272 		 * if it is after search, then we have user defined regexps+
273 		 * a searched regexp to highlight
274 		 */
275 		/* loop over all the lines currently in the window */
276 		for (unsigned i = pos; (i < lines) && (i < pos + maxy - 2); i++)
277 		{
278 			char *str = message[i];
279 
280 			/* loop over all regexps we might want to show */
281 			int j;
282 			for (j = 0; j < maxregexp; j++)
283 			{
284 				/* check if this regexp is present on this line */
285 				while (!regexec(&h_regexp[j], str, 1, pmatch, 0))
286 				{
287 					int x, y;
288 					char tmp;
289 
290 					/* yes, found something, so highlight it */
291 					int n = pmatch[0].rm_eo - pmatch[0].rm_so;
292 
293 					if (n==0) { /* matched empty string! */
294 						/* display error message */
295 						char msg[81];
296 						snprintf(msg, 81, "%s",
297 								_("Warning: matched empty string") );
298 						attrset(bottomline);
299 						mvhline(maxy - 1, 0, ' ', maxx);
300 						mvaddstr(maxy - 1, 0, msg);
301 						move(0, 0);
302 						attrset(normal);
303 
304 						break;
305 					}
306 
307 					/* point str at start of match */
308 					str += pmatch[0].rm_so;
309 
310 					/* calculate position on screen */
311 					x = calculate_len(message[i], str);
312 					y = i - pos + 1;
313 
314 					/* save the char after the end of the match,
315 					 * and replace it by \0 */
316 					tmp = str[n];
317 					str[n] = 0;
318 
319 					/* write out the highlighted match to screen */
320 					attrset(searchhighlight);
321 					mvaddstr(y, x, str);
322 					attrset(normal);
323 
324 					/* restore the original char at the end of the match */
325 					str[n] = tmp;
326 
327 					/* skip past this match */
328 					str += n;
329 				}
330 			}
331 		}
332 	}
333 
334 #endif
335 }
336