1 /* $Id: output_apropos.c,v 1.12 2003/04/17 03:03:41 jtalkington Exp $ */
2
3 #include "common.h"
4 #include "output_apropos.h"
5
6 #ifndef DISABLE_APROPOS
7 /* the tree of all of the apropos_node s
8 */
9 static struct section_node *apropos_tree = NULL;
10
11 /* output_apropos()
12 * outputs the results of apropos sorted by section and with references back
13 * to the program's URL
14 */
15 void
output_apropos(char * keyword)16 output_apropos(char *keyword) {
17 FILE *ap_fh = NULL;
18 char line[BUFSIZ];
19 char *command = NULL;
20
21 if((Config.apropos != NULL) && ((Config.disabled & D_APROPOS) == 0)) {
22 command = strdup(Config.apropos);
23 } else {
24 output_apropos_denied();
25 return;
26 }
27
28
29 command = str_app_s(command, " ");
30 command = str_app_s(command, keyword);
31
32 output_header("Keyword search", keyword);
33 if((ap_fh = popen(command, "r")) == NULL) {
34 printf("<h2>Error opening pipe to: %s</h2>\n", command);
35 output_footer();
36 return;
37 } else {
38 while(fgets(line, sizeof(line), ap_fh) != NULL) {
39 apr_add_line(line);
40 }
41
42 printf("<h2>Keyword search for %s results:</h2>\n<hr />\n", keyword);
43 printf("<table width=\"100%%\">\n");
44 output_section_node(&apropos_tree);
45 printf("</table>\n");
46 output_footer();
47 pclose(ap_fh);
48 #ifdef M2W_CLEANUP
49 cleanup_apropos_section(&apropos_tree);
50 apropos_tree = NULL;
51 #endif /* M2W_CLEANUP */
52 }
53
54 free(command);
55
56 }
57
58 /* break down the line and add links if we have are not in command mode */
59 void
apr_add_line(char * line)60 apr_add_line(char *line) {
61 char *linked_line = NULL;
62 char *program = NULL;
63 char *section = NULL;
64 char *prog_start = NULL;
65 char *prog_end = NULL;
66 char *sec_start = NULL;
67 char *sec_end = NULL;
68 char *white_start = NULL;
69 char *script_name = get_query_value(SCRIPT_NAME);
70 char *prog_extra = calloc(1,1);
71
72 if(line == NULL) {
73 return;
74 }
75
76 /* kill the newline */
77 memset(line + strlen(line) - 1, '\0', 1);
78
79 prog_start = line;
80 prog_end = prog_start;
81
82 /* get the program name */
83 while(*prog_end != ' ' && *prog_end != '\t' && *prog_end != '(') {
84 prog_end++;
85 }
86
87 program = strndup(prog_start, prog_end - prog_start);
88
89 /* extract the section */
90 sec_start = strchr(prog_end, '(');
91
92 if(sec_start != NULL) {
93
94 sec_end = strchr(sec_start, ')');
95
96 if(sec_end != NULL) {
97
98 section = strndup(sec_start + 1, sec_end - (sec_start + 1));
99
100 white_start = sec_start;
101
102 while(white_start > prog_end && (*(white_start - 1) == ' ' || *(white_start - 1) == '\t')) {
103 white_start--;
104 }
105
106 /* get any non whitespace extras after the program name but before
107 * the section start (for entries with [foo] after the program name
108 */
109
110 while(prog_end < white_start) {
111 prog_extra = str_app_c(prog_extra, *prog_end);
112 prog_end++;
113 }
114
115 /* get to the start of the description (-) */
116 while(*sec_end != '-') {
117 sec_end++;
118 }
119
120 if(script_name != NULL) {
121 linked_line = calloc(1, strlen(APROPOS_HREF) + (2 * (strlen(program) + 1)) + (strlen(prog_extra) + 1) + (strlen(section) + 1) + (strlen(script_name) + 1) + strlen(line) + 1);
122 sprintf(linked_line, APROPOS_HREF, script_name, program, section, program, prog_extra, section, sec_end);
123
124 } else {
125 linked_line = strdup(line);
126 }
127 } else {
128 linked_line = strdup(line);
129 }
130 } else {
131 linked_line = strdup(line);
132 }
133
134 apr_add_to_tree(&apropos_tree, program, section, linked_line);
135
136 if(program != NULL) {
137 free(program);
138 program = NULL;
139 }
140
141 if(prog_extra != NULL) {
142 free(prog_extra);
143 prog_extra = NULL;
144 }
145
146 if(section != NULL) {
147 free(section);
148 section = NULL;
149 }
150
151 free(linked_line);
152 linked_line = NULL;
153 }
154
155 /* apr_add_to_tree()
156 * adds an apropos section node and program node to the tree
157 */
158 void
apr_add_to_tree(struct section_node ** sec_node,char * program,char * section,char * line)159 apr_add_to_tree(struct section_node **sec_node, char *program, char *section, char *line) {
160 int result = 0;
161
162 if((*sec_node) == NULL) {
163 (*sec_node) = calloc(1, sizeof(struct section_node));
164
165 (*sec_node)->left = NULL;
166 (*sec_node)->right = NULL;
167 (*sec_node)->data = NULL;
168 if(section != NULL) {
169 (*sec_node)->name = strdup(section);
170 } else {
171 (*sec_node)->name = strdup(program);
172 };
173 apr_add_prog(&(*sec_node)->data, program, line);
174 } else {
175 result = strcmp((*sec_node)->name, section);
176
177 if(result == 0) {
178 apr_add_prog(&(*sec_node)->data, program, line);
179 } else if(result < 0) {
180 apr_add_to_tree(&(*sec_node)->right, program, section, line);
181 } else {
182 apr_add_to_tree(&(*sec_node)->left, program, section, line);
183 }
184 }
185 }
186
187 /* apr_add_prog()
188 * adds a program to an apropos_node tree
189 */
190 void
apr_add_prog(struct apropos_node ** node,char * program,char * line)191 apr_add_prog(struct apropos_node **node, char *program, char *line) {
192 int result = 0;
193
194 if((*node) == NULL) {
195 (*node) = calloc(1, sizeof(struct apropos_node));
196
197 (*node)->left = NULL;
198 (*node)->right = NULL;
199 (*node)->name = strdup(program);
200 (*node)->line = strdup(line);
201 } else {
202 result = strcmp((*node)->name, program);
203
204 if(result == 0) {
205 /* it already exists, so just dump it */
206 return;
207 } else if(result < 0) {
208 apr_add_prog(&(*node)->right, program, line);
209 } else {
210 apr_add_prog(&(*node)->left, program, line);
211 }
212 }
213 }
214
215 /* output_section_node()
216 * outputs all of the elements of the apropos_tree recursively (and therefore
217 * sorted by section
218 */
219 void
output_section_node(struct section_node ** section)220 output_section_node(struct section_node **section) {
221
222 if((*section) == NULL) {
223 return;
224 }
225
226 if((*section)->left != NULL) {
227 output_section_node(&(*section)->left);
228 }
229
230 output_apropos_node(&(*section)->data);
231
232 if((*section)->right != NULL) {
233 output_section_node(&(*section)->right);
234 }
235 }
236
237 /* output_apropos_node()
238 * outputs the program node of a section recursively
239 */
240
241 void
output_apropos_node(struct apropos_node ** node)242 output_apropos_node(struct apropos_node **node) {
243
244 if((*node) == NULL) {
245 return;
246 }
247
248 if((*node)->left != NULL) {
249 output_apropos_node(&(*node)->left);
250 }
251
252 printf("%s\n", (*node)->line);
253
254 output_apropos_node(&(*node)->right);
255 }
256
257 #ifdef M2W_CLEANUP
258
259 /* cleanup_apropos_section()
260 * cleans up a section node of the apropos_tree
261 */
262 void
cleanup_apropos_section(struct section_node ** node)263 cleanup_apropos_section(struct section_node **node) {
264 struct section_node *right = NULL;
265
266 if((*node) == NULL) {
267 return;
268 } else {
269 right = (*node)->right;
270 }
271
272 if((*node)->left != NULL) {
273 cleanup_apropos_section(&(*node)->left);
274 (*node)->left = NULL;
275 }
276
277 cleanup_apropos_node(&(*node)->data);
278 (*node)->data = NULL;
279
280 free((*node)->name);
281 (*node)->name = NULL;
282
283 free(*node);
284
285 if(right != NULL) {
286 cleanup_apropos_section(&right);
287 }
288 }
289
290 /* cleanup_apropos_node()
291 * cleans up the apropos_node part of a section node
292 */
293 void
cleanup_apropos_node(struct apropos_node ** node)294 cleanup_apropos_node(struct apropos_node **node) {
295 struct apropos_node *right = NULL;
296
297 if((*node) == NULL) {
298 return;
299 } else {
300 right = (*node)->right;
301 }
302
303 if((*node)->left != NULL) {
304 cleanup_apropos_node(&(*node)->left);
305 (*node)->left = NULL;
306 }
307
308 free((*node)->name);
309 (*node)->name = NULL;
310
311 free((*node)->line);
312 (*node)->line = NULL;
313
314 free(*node);
315
316 if(right != NULL) {
317 cleanup_apropos_node(&right);
318 }
319 }
320 #endif /* M2W_CLEANUP */
321
322 #else /* DISABLE_APROPOS */
323
324 /* wrapper for if apropos is disabled */
325 void
output_apropos(char * keyword)326 output_apropos(char *keyword) {
327 output_apropos_denied();
328 }
329
330 #endif /* DISABLE_APROPOS */
331
332 /* prints out a page if apropos searching is disabled */
333 void
output_apropos_denied()334 output_apropos_denied() {
335 output_header("Keyword Search Disabled", NULL);
336 printf("<h2>Keyword (apropos) search disabled</h2>\n");
337 output_footer();
338 }
339