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