1 /*
2  * (C) Copyright 2008-2015 Diomidis Spinellis
3  *
4  * This file is part of CScout.
5  *
6  * CScout is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * CScout is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with CScout.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *
20  * HTML utility functions
21  *
22  */
23 
24 #include <map>
25 #include <string>
26 #include <deque>
27 #include <vector>
28 #include <stack>
29 #include <iterator>
30 #include <iostream>
31 #include <fstream>
32 #include <list>
33 #include <set>
34 #include <utility>
35 #include <functional>
36 #include <algorithm>		// set_difference
37 #include <cctype>
38 #include <sstream>		// ostringstream
39 #include <cstdio>		// perror, rename
40 #include <cstdlib>		// atoi
41 #include <cerrno>		// errno
42 
43 #include "swill.h"
44 #include "getopt.h"
45 
46 #include "cpp.h"
47 #include "debug.h"
48 #include "error.h"
49 #include "parse.tab.h"
50 #include "attr.h"
51 #include "metrics.h"
52 #include "fileid.h"
53 #include "tokid.h"
54 #include "token.h"
55 #include "ptoken.h"
56 #include "fchar.h"
57 #include "pltoken.h"
58 #include "macro.h"
59 #include "pdtoken.h"
60 #include "eclass.h"
61 #include "ctoken.h"
62 #include "type.h"
63 #include "stab.h"
64 #include "fdep.h"
65 #include "version.h"
66 #include "call.h"
67 #include "html.h"
68 #include "fileutils.h"
69 #include "option.h"
70 
71 /*
72  * Return as a C string the HTML equivalent of character c
73  * Handles tab-stop expansion provided all output is processed through this
74  * function
75  */
76 const char *
html(char c)77 html(char c)
78 {
79 	static char str[2];
80 	static int column = 0;
81 	static vector<string> spaces(0);
82 	int space_idx;
83 
84 	switch (c) {
85 	case '&': column++; return "&amp;";
86 	case '<': column++; return "&lt;";
87 	case '>': column++; return "&gt;";
88 	case '"': column++; return "&quot;";
89 	case ' ': column++; return "&nbsp;";
90 	case '\t':
91 		if ((int)(spaces.size()) != Option::tab_width->get()) {
92 			spaces.resize(Option::tab_width->get());
93 			for (int i = 0; i < Option::tab_width->get(); i++) {
94 				string t;
95 				for (int j = 0; j < Option::tab_width->get() - i; j++)
96 					t += "&nbsp;";
97 				spaces[i] = t;
98 			}
99 		}
100 		space_idx = column % Option::tab_width->get();
101 		if (DP())
102 			cout << "Tab; " << " column before:" << column << " space_idx: " << space_idx << endl;
103 		column += 8 - space_idx;
104 		return spaces[space_idx].c_str();
105 	case '\n':
106 		column = 0;
107 		return "<br>\n";
108 	case '\r':
109 		column = 0;
110 		return "";
111 	case '\f':
112 		column = 0;
113 		return "<br><hr><br>\n";
114 	default:
115 		column++;
116 		str[0] = c;
117 		return str;
118 	}
119 }
120 
121 // HTML-encode the given string
122 string
html(const string & s)123 html(const string &s)
124 {
125 	string r;
126 
127 	for (string::const_iterator i = s.begin(); i != s.end(); i++)
128 		r += html(*i);
129 	return r;
130 }
131 
132 // Output s as HTML in of
133 void
html_string(FILE * of,string s)134 html_string(FILE *of, string s)
135 {
136 	for (string::const_iterator i = s.begin(); i != s.end(); i++)
137 		fputs(html(*i), of);
138 }
139 
140 
141 // Create a new HTML file with a given filename and title
142 // The heading, if not given, will be the same as the title
143 void
html_head(FILE * of,const string fname,const string title,const char * heading)144 html_head(FILE *of, const string fname, const string title, const char *heading)
145 {
146 	swill_title(title.c_str());
147 	if (DP())
148 		cerr << "Write to " << fname << endl;
149 	fprintf(of,
150 		"<!doctype html public \"-//IETF//DTD HTML//EN\">\n"
151 		"<html>\n"
152 		"<head>\n"
153 		"<meta name=\"GENERATOR\" content=\"CScout %s - %s\">\n",
154 		Version::get_revision().c_str(),
155 		Version::get_date().c_str());
156 	fputs(
157 		"<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">"
158 		"<style type=\"text/css\" >"
159 		"<!--\n", of);
160 
161 	ifstream in;
162 	string css_fname;
163 	if (cscout_input_file("style.css", in, css_fname)) {
164 		int val;
165 		while ((val = in.get()) != EOF)
166 			putc(val, of);
167 	} else
168 		fputs(
169 		#include "css.c"
170 		, of);
171 	fputs(
172 		"-->"
173 		"</style>"
174 		"</head>", of);
175 	fprintf(of,
176 		"<title>%s</title>\n"
177 		"</head>\n"
178 		"<body>\n"
179 		"<h1>%s</h1>\n",
180 		title.c_str(),
181 		heading ? heading : title.c_str());
182 }
183 
184 // And an HTML file end
185 void
html_tail(FILE * of)186 html_tail(FILE *of)
187 {
188 	extern Attributes::size_type current_project;
189 
190 	if (current_project)
191 		fprintf(of, "<p> <b>Project %s is currently selected</b>\n", Project::get_projname(current_project).c_str());
192 	fprintf(of,
193 		"<p>"
194 		"<a href=\"index.html\">Main page</a>\n"
195 		" &mdash; Web: "
196 		"<a href=\"http://www.spinellis.gr/cscout\">Home</a>\n"
197 		"<a href=\"http://www.spinellis.gr/cscout/doc/index.html\">Manual</a>\n"
198 		"<br><hr><div class=\"footer\">CScout %s &mdash; %s",
199 		Version::get_revision().c_str(),
200 		Version::get_date().c_str());
201 	fprintf(of, " &mdash; Licensed under the GNU General Public License.");
202 	fprintf(of, "</div></body></html>\n");
203 }
204 
205 // Return a function's label, based on the user's preferences
206 string
file_label(Fileid f,bool hyperlink)207 file_label(Fileid f, bool hyperlink)
208 {
209 	string result;
210 	char buff[256];
211 
212 	if (hyperlink) {
213 		snprintf(buff, sizeof(buff), "<a href=\"file.html?id=%d\">", f.get_id());
214 		result = buff;
215 	}
216 	switch (Option::fgraph_show->get()) {
217 	case 'p':			// Show complete paths
218 		result += f.get_path() + "/";
219 		/* FALLTHROUGH */
220 	case 'n':			// Show only file names
221 		result += f.get_fname();
222 		break;
223 	case 'e':			// Show only edges
224 		result += " ";
225 		break;
226 	}
227 	if (hyperlink)
228 		result += "</a>";
229 	return (result);
230 }
231 
232 // Return a function's label, based on the user's preferences
233 string
function_label(Call * f,bool hyperlink)234 function_label(Call *f, bool hyperlink)
235 {
236 	string result;
237 	char buff[256];
238 
239 	if (hyperlink) {
240 		snprintf(buff, sizeof(buff), "<a href=\"fun.html?f=%p\">", f);
241 		result = buff;
242 	}
243 	if (Option::show_function_type->get()) {
244 		if (f->is_file_scoped())
245 			result += "static:";
246 		else
247 			result += "public:";
248 	}
249 	if (Option::cgraph_show->get() == 'f')		// Show files
250 		result += f->get_site().get_fileid().get_fname() + ":";
251 	else if (Option::cgraph_show->get() == 'p')	// Show paths
252 		result += f->get_site().get_fileid().get_path() + ":";
253 	if (Option::cgraph_show->get() != 'e')		// Empty labels
254 		result += f->get_name();
255 	if (hyperlink)
256 		result += "</a>";
257 	return (result);
258 }
259 
260 // Display a system error on the HTML output.
261 void
html_perror(FILE * of,const string & user_msg,bool svg)262 html_perror(FILE *of, const string &user_msg, bool svg)
263 {
264 	string error_msg(user_msg + ": " + string(strerror(errno)) + "\n");
265 	fputs(error_msg.c_str(), stderr);
266 	if (svg)
267 		fprintf(of, "<?xml version=\"1.0\" ?>\n"
268 			"<svg>\n"
269 			"<text  x=\"20\" y=\"50\" >%s</text>\n"
270 			"</svg>\n", error_msg.c_str());
271 	else {
272 		fputs(error_msg.c_str(), of);
273 		fputs("</p><p>The operation you requested is incomplete.  "
274 			"Please correct the underlying cause, and (if possible) return to the "
275 			"CScout <a href=\"index.html\">main page</a> to retry the operation.</p>", of);
276 	}
277 }
278 
279 // Display a non-system error on the HTML output.
280 void
html_error(FILE * of,const string & error_msg)281 html_error(FILE *of, const string &error_msg)
282 {
283 	fputs(error_msg.c_str(), stderr);
284 	fputs(error_msg.c_str(), of);
285 	fputs("</p><p>The operation you requested is incomplete.  "
286 		"Please correct the underlying cause, and (if possible) return to the "
287 		"CScout <a href=\"index.html\">main page</a> to retry the operation.</p>", of);
288 }
289