1 /*
2  * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005,
3  *	2010
4  *	Tama Communications Corporation
5  *
6  * This file is part of GNU GLOBAL.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32 #include "queue.h"
33 #include "global.h"
34 #include "cache.h"
35 #include "htags.h"
36 #include "path2url.h"
37 #include "common.h"
38 
39 /*
40  * makedefineindex: make definition index (including alphabetic index)
41  *
42  *	@param[in]	file		definition index file
43  *	@param[in]	total		definitions total
44  *	@param[out]	defines		@defines
45  *	Globals used (input):
46  *		tag cache	  XXX: should this be global output, not input?
47  */
48 int
makedefineindex(const char * file,int total,STRBUF * defines)49 makedefineindex(const char *file, int total, STRBUF *defines)
50 {
51 	int count = 0;
52 	int alpha_count = 0;
53 	FILEOP *fileop_MAP = NULL, *fileop_DEFINES, *fileop_ALPHA = NULL;
54 	FILE *MAP = NULL;
55 	FILE *DEFINES, *STDOUT, *TAGS, *ALPHA = NULL;
56 	STRBUF *sb = strbuf_open(0);
57 	STRBUF *url = strbuf_open(0);
58 	/* Index link */
59 	const char *target = (Fflag) ? "mains" : "_top";
60 	const char *indexlink;
61 	const char *index_string = "Index Page";
62 	char command[1024], buf[1024], alpha[32], alpha_f[32], *_;
63 
64 	if (!aflag && !Fflag)
65 		indexlink = "mains";
66 	else if (Fflag)
67 		indexlink = "../defines";
68 	else
69 		indexlink = "../mains";
70 
71 	if (map_file) {
72 		fileop_MAP = open_output_file(makepath(distpath, "MAP", NULL), 0);
73 		MAP = get_descripter(fileop_MAP);
74 	}
75 	fileop_DEFINES = open_output_file(makepath(distpath, file, NULL), 0);
76 	DEFINES = get_descripter(fileop_DEFINES);
77 	fputs_nl(gen_page_begin(title_define_index, TOPDIR), DEFINES);
78 	fputs_nl(body_begin, DEFINES);
79 	fputs(header_begin, DEFINES);
80 	if (Fflag)
81 		fputs(gen_href_begin(NULL, "defines", normal_suffix, NULL), DEFINES);
82 	fputs(title_define_index, DEFINES);
83 	if (Fflag)
84 		fputs(gen_href_end(), DEFINES);
85 	fputs_nl(header_end, DEFINES);
86 	if (!aflag && !Fflag) {
87 		fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), DEFINES);
88 		if (Iflag)
89 			fputs(gen_image(CURRENT, back_icon, ".."), DEFINES);
90 		else
91 			fputs("[..]", DEFINES);
92 		fputs_nl(gen_href_end(), DEFINES);
93 	}
94 	if (!aflag) {
95 		if (!no_order_list)
96 			fputs_nl(list_begin, DEFINES);
97 	}
98 	/*
99 	 * map DEFINES to STDOUT.
100 	 */
101 	STDOUT = DEFINES;
102 	snprintf(command, sizeof(command), PQUOTE "%s -c" PQUOTE, quote_shell(global_path));
103 	if ((TAGS = popen(command, "r")) == NULL)
104 		die("cannot execute '%s'.", command);
105 	alpha[0] = '\0';
106 	while ((_ = strbuf_fgets(sb, TAGS, STRBUF_NOCRLF)) != NULL) {
107 		const char *tag, *line;
108 		char guide[1024], url_for_map[1024];
109 
110 		count++;
111 		tag = _;
112 		message(" [%d/%d] adding %s", count, total, tag);
113 		if (aflag && (alpha[0] == '\0' || !locatestring(tag, alpha, MATCH_AT_FIRST))) {
114 			const char *msg = (alpha_count == 1) ? "definition" : "definitions";
115 			int c;
116 
117 			if (alpha[0]) {
118 				char tmp[128];
119 				snprintf(tmp, sizeof(tmp), "%d %s", alpha_count, msg);
120 				strbuf_puts(defines, gen_href_begin_with_title("defines", alpha_f, HTML, NULL, tmp));
121 				strbuf_sprintf(defines, "[%s]", alpha);
122 				strbuf_puts_nl(defines, gen_href_end());
123 				alpha_count = 0;
124 				if (!no_order_list)
125 					fputs_nl(list_end, ALPHA);
126 				else
127 					fputs_nl(br, ALPHA);
128 				fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
129 				if (Iflag)
130 					fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
131 				else
132 					fputs("[..]", ALPHA);
133 				fputs_nl(gen_href_end(), ALPHA);
134 				fputs_nl(body_end, ALPHA);
135 				fputs_nl(gen_page_end(), ALPHA);
136 				close_file(fileop_ALPHA);
137 				html_count++;
138 			}
139 			/*
140 			 * setup index char (for example, 'a' of '[a]').
141 			 * alpha is used for display.
142 			 * alpha_f is used for part of path.
143 			 */
144 			c = (unsigned char)*tag;
145 			if (c > 127) {
146 				int i2 = *(tag + 1) & 0xff;
147 				/*
148 				 * for multi-byte(EUC) code.
149 				 */
150 				alpha[0] = *tag;
151 				alpha[1] = *(tag + 1);
152 				alpha[2] = '\0';
153 				snprintf(alpha_f, sizeof(alpha_f), "%03d%03d", c, i2);
154 			} else if (isalpha(c) || c == '_') {
155 				alpha[0] = *tag;
156 				alpha[1] = '\0';
157 				/*
158 				 * for CD9660 or FAT file system
159 				 */
160 				if (islower(c)) {
161 					alpha_f[0] = 'l';
162 					alpha_f[1] = *tag;
163 					alpha_f[2] = '\0';
164 				} else {
165 					alpha_f[0] = *tag;
166 					alpha_f[1] = '\0';
167 				}
168 			} else {
169 				alpha[0] = *tag;
170 				alpha[1] = '\0';
171 				snprintf(alpha_f, sizeof(alpha_f), "%03d", c);
172 			}
173 			snprintf(buf, sizeof(buf), "%s/defines/%s.%s", distpath, alpha_f, HTML);
174 			fileop_ALPHA = open_output_file(buf, 0);
175 			ALPHA = get_descripter(fileop_ALPHA);
176 			snprintf(buf, sizeof(buf), "[%s]", alpha);
177 			fputs_nl(gen_page_begin(buf, SUBDIR), ALPHA);
178 			fputs_nl(body_begin, ALPHA);
179 			fprintf(ALPHA, "%s[%s]%s\n", header_begin, alpha, header_end);
180 			fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
181 			if (Iflag)
182 				fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
183 			else
184 				fputs("[..]", ALPHA);
185 			fputs_nl(gen_href_end(), ALPHA);
186 			if (!no_order_list)
187 				fputs_nl(list_begin, ALPHA);
188 			else
189 				fprintf(ALPHA, "%s%s\n", br, br);
190 			STDOUT = ALPHA;
191 		}
192 		alpha_count++;
193 		/*
194 		 * generating url for function definition.
195 	 	 */
196 		line = cache_get(GTAGS, tag);
197 		strbuf_reset(url);
198 
199 		if (line == NULL)
200 			die("internal error in makedefineindex().");
201 		/*
202 		 * About the format of 'line', please see the head comment of cache.c.
203 		 */
204 		if (*line == ' ') {
205 			const char *fid = line + 1;
206 			const char *enumber = nextstring(fid);
207 
208 			snprintf(url_for_map, sizeof(url_for_map), "%s/%s.%s",
209 				DEFS, fid, HTML);
210 			if (dynamic) {
211 				if (*action != '/' && aflag)
212 					strbuf_puts(url, "../");
213 				strbuf_puts(url, action);
214 				strbuf_sprintf(url, "?pattern=%s%stype=definitions", tag, quote_amp);
215 			} else {
216 				if (aflag)
217 					strbuf_puts(url, "../");
218 				strbuf_sprintf(url, "%s/%s.%s", DEFS, fid, HTML);
219 			}
220 			snprintf(guide, sizeof(guide), "Multiple defined in %s places.", enumber);
221 		} else {
222 			const char *lno = line;
223 			const char *fid = nextstring(line);
224 			const char *path = gpath_fid2path(fid, NULL);
225 
226 			path += 2;		/* remove './' */
227 			snprintf(url_for_map, sizeof(url_for_map), "%s/%s.%s#L%s",
228 				SRCS, fid, HTML, lno);
229 			if (aflag)
230 				strbuf_puts(url, "../");
231 			strbuf_sprintf(url, "%s/%s.%s#L%s", SRCS, fid, HTML, lno);
232 			snprintf(guide, sizeof(guide), "Defined at %s in %s.", lno, path);
233 		}
234 		if (!no_order_list)
235 			fputs(item_begin, STDOUT);
236 		fputs(gen_href_begin_with_title_target(NULL, strbuf_value(url), NULL, NULL, guide, target), STDOUT);
237 		fputs(tag, STDOUT);
238 		fputs(gen_href_end(), STDOUT);
239 		if (!no_order_list)
240 			fputs(item_end, STDOUT);
241 		else
242 			fputs(br, STDOUT);
243 		fputc('\n', STDOUT);
244 		if (map_file)
245 			fprintf(MAP, "%s\t%s\n", tag, url_for_map);
246 	}
247 	if (pclose(TAGS) != 0)
248 		die("terminated abnormally '%s' (errno = %d).", command, errno);
249 	if (aflag && alpha[0]) {
250 		char tmp[128];
251 		const char *msg = (alpha_count == 1) ? "definition" : "definitions";
252 
253 		snprintf(tmp, sizeof(tmp), "%d %s", alpha_count, msg);
254 		strbuf_puts(defines, gen_href_begin_with_title("defines", alpha_f, HTML, NULL, tmp));
255 		strbuf_sprintf(defines, "[%s]", alpha);
256 		strbuf_puts_nl(defines, gen_href_end());
257 		if (!no_order_list)
258 			fputs_nl(list_end, ALPHA);
259 		else
260 			fputs_nl(br, ALPHA);
261 		fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
262 		if (Iflag)
263 			fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
264 		else
265 			fputs("[..]", ALPHA);
266 		fputs_nl(gen_href_end(), ALPHA);
267 		fputs_nl(body_end, ALPHA);
268 		fputs_nl(gen_page_end(), ALPHA);
269 		close_file(fileop_ALPHA);
270 		html_count++;
271 
272 		fputs(strbuf_value(defines), DEFINES);
273 	}
274 	if (!no_order_list && !aflag)
275 		fputs_nl(list_end, DEFINES);
276 	if (!aflag && !Fflag) {
277 		fputs(gen_href_begin_with_title(NULL, "mains", normal_suffix, NULL, index_string), DEFINES);
278 		if (Iflag)
279 			fputs(gen_image(CURRENT, back_icon, ".."), DEFINES);
280 		else
281 			fputs("[..]", DEFINES);
282 		fputs_nl(gen_href_end(), DEFINES);
283 	}
284 	fputs_nl(body_end, DEFINES);
285 	fputs_nl(gen_page_end(), DEFINES);
286 	close_file(fileop_DEFINES);
287 	html_count++;
288 	if (map_file)
289 		close_file(fileop_MAP);
290 	strbuf_close(sb);
291 	strbuf_close(url);
292 	return count;
293 }
294