Branch data Line data Source code
1 : : /* Automatic generation of links into GCC's documentation.
2 : : Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "pretty-print.h"
25 : : #include "pretty-print-urlifier.h"
26 : : #include "gcc-urlifier.h"
27 : : #include "opts.h"
28 : : #include "options.h"
29 : : #include "selftest.h"
30 : :
31 : : namespace {
32 : :
33 : : /* Concrete subclass of urlifier for generating links into
34 : : GCC's HTML documentation. */
35 : :
36 : 4 : class gcc_urlifier : public urlifier
37 : : {
38 : : public:
39 : 587314 : gcc_urlifier (unsigned int lang_mask)
40 : 587314 : : m_lang_mask (lang_mask)
41 : : {}
42 : :
43 : : char *get_url_for_quoted_text (const char *p, size_t sz) const final override;
44 : :
45 : : label_text get_url_suffix_for_quoted_text (const char *p, size_t sz) const;
46 : : /* We use ATTRIBUTE_UNUSED as this helper is called only from ASSERTs. */
47 : : label_text get_url_suffix_for_quoted_text (const char *p) const ATTRIBUTE_UNUSED;
48 : :
49 : : private:
50 : : label_text get_url_suffix_for_option (const char *p, size_t sz) const;
51 : :
52 : : static char *
53 : : make_doc_url (const char *doc_url_suffix);
54 : :
55 : : unsigned int m_lang_mask;
56 : : };
57 : :
58 : : /* class gcc_urlifier : public urlifier. */
59 : :
60 : : /* Manage a hard-coded mapping from quoted string to URL suffixes
61 : : in gcc-urlifier.def */
62 : :
63 : : #define DOC_URL(QUOTED_TEXT, URL_SUFFIX) \
64 : : { (QUOTED_TEXT), (URL_SUFFIX) }
65 : :
66 : : static const struct
67 : : {
68 : : const char *quoted_text;
69 : : const char *url_suffix;
70 : : } doc_urls[] = {
71 : :
72 : : #include "gcc-urlifier.def"
73 : :
74 : : };
75 : :
76 : : /* Implementation of urlifier::get_url_for_quoted_text vfunc for GCC
77 : : diagnostics. */
78 : :
79 : : char *
80 : 0 : gcc_urlifier::get_url_for_quoted_text (const char *p, size_t sz) const
81 : : {
82 : 0 : label_text url_suffix = get_url_suffix_for_quoted_text (p, sz);
83 : 0 : if (url_suffix.get ())
84 : 0 : return make_doc_url (url_suffix.get ());
85 : : return nullptr;
86 : 0 : }
87 : :
88 : : /* Look for a URL for the quoted string (P, SZ).
89 : : Return the url suffix if found, or nullptr otherwise. */
90 : :
91 : : label_text
92 : 92 : gcc_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const
93 : : {
94 : 92 : if (sz == 0)
95 : 4 : return label_text ();
96 : :
97 : : /* If this is an option, look up the option and see if we have
98 : : a URL for it. */
99 : 88 : if (p[0] == '-')
100 : : {
101 : 8 : label_text suffix = get_url_suffix_for_option (p, sz);
102 : 8 : if (suffix.get ())
103 : 8 : return suffix;
104 : 8 : }
105 : :
106 : : /* Otherwise, look within the hard-coded data table in gcc-urlifier.def.
107 : :
108 : : Binary search. This assumes that the quoted_text fields of doc_urls
109 : : are in sorted order. */
110 : 80 : int min = 0;
111 : 80 : int max = ARRAY_SIZE (doc_urls) - 1;
112 : 288 : while (true)
113 : : {
114 : 288 : if (min > max)
115 : 8 : return label_text ();
116 : 280 : int midpoint = (min + max) / 2;
117 : 280 : gcc_assert ((size_t)midpoint < ARRAY_SIZE (doc_urls));
118 : 280 : int cmp = strncmp (p, doc_urls[midpoint].quoted_text, sz);
119 : 280 : if (cmp == 0)
120 : : {
121 : 80 : if (doc_urls[midpoint].quoted_text[sz] == '\0')
122 : 72 : return label_text::borrow (doc_urls[midpoint].url_suffix);
123 : : else
124 : 8 : max = midpoint - 1;
125 : : }
126 : 200 : else if (cmp < 0)
127 : 68 : max = midpoint - 1;
128 : : else
129 : 132 : min = midpoint + 1;
130 : : }
131 : :
132 : : /* Not found. */
133 : : return label_text ();
134 : : }
135 : :
136 : : /* For use in selftests. */
137 : :
138 : : label_text
139 : 92 : gcc_urlifier::get_url_suffix_for_quoted_text (const char *p) const
140 : : {
141 : 92 : return get_url_suffix_for_quoted_text (p, strlen (p));
142 : : }
143 : :
144 : : /* Look for a URL for the quoted string (P, SZ) that appears to be
145 : : an option.
146 : : Return the url suffix if found, or nullptr otherwise. */
147 : :
148 : : label_text
149 : 8 : gcc_urlifier::get_url_suffix_for_option (const char *p, size_t sz) const
150 : : {
151 : : /* Look up this option
152 : :
153 : : find_opt does a binary search, taking a 0-terminated string,
154 : : and skipping the leading '-'.
155 : :
156 : : We have a (pointer,size) pair that doesn't necessarily have a
157 : : terminator.
158 : : Additionally, we could have one of the e.g. "-Wno-" variants of
159 : : the option, which find_opt doesn't handle.
160 : :
161 : : Hence we need to create input for find_opt in a temporary buffer. */
162 : 8 : char *option_buffer;
163 : :
164 : 8 : const char *new_prefix;
165 : 8 : if (const char *old_prefix = get_option_prefix_remapping (p, sz, &new_prefix))
166 : : {
167 : : /* We have one of the variants; generate a buffer containing a copy
168 : : that maps from the old prefix to the new prefix
169 : : e.g. given "-Wno-suffix", generate "-Wsuffix". */
170 : 4 : gcc_assert (old_prefix[0] == '-');
171 : 4 : gcc_assert (new_prefix);
172 : 4 : gcc_assert (new_prefix[0] == '-');
173 : :
174 : 4 : const size_t old_prefix_len = strlen (old_prefix);
175 : 4 : gcc_assert (old_prefix_len <= sz);
176 : 4 : const size_t suffix_len = sz - old_prefix_len;
177 : 4 : const size_t new_prefix_len = strlen (new_prefix);
178 : 4 : const size_t new_sz = new_prefix_len + suffix_len + 1;
179 : :
180 : 4 : option_buffer = (char *)xmalloc (new_sz);
181 : 4 : memcpy (option_buffer, new_prefix, new_prefix_len);
182 : : /* Copy suffix. */
183 : 4 : memcpy (option_buffer + new_prefix_len, p + old_prefix_len, suffix_len);
184 : : /* Terminate. */
185 : 4 : option_buffer[new_prefix_len + suffix_len] = '\0';
186 : : }
187 : : else
188 : : {
189 : : /* Otherwise we can simply create a 0-terminated clone of the string. */
190 : 4 : gcc_assert (sz > 0);
191 : 4 : gcc_assert (p[0] == '-');
192 : 4 : option_buffer = xstrndup (p, sz);
193 : : }
194 : :
195 : 8 : size_t opt = find_opt (option_buffer + 1, m_lang_mask);
196 : 8 : free (option_buffer);
197 : :
198 : 8 : if (opt >= N_OPTS)
199 : : /* Option not recognized. */
200 : 0 : return label_text ();
201 : :
202 : 8 : return get_option_url_suffix (opt, m_lang_mask);
203 : : }
204 : :
205 : : char *
206 : 0 : gcc_urlifier::make_doc_url (const char *doc_url_suffix)
207 : : {
208 : 0 : if (!doc_url_suffix)
209 : : return nullptr;
210 : :
211 : 0 : return concat (DOCUMENTATION_ROOT_URL, doc_url_suffix, nullptr);
212 : : }
213 : :
214 : : } // anonymous namespace
215 : :
216 : : urlifier *
217 : 587310 : make_gcc_urlifier (unsigned int lang_mask)
218 : : {
219 : 587310 : return new gcc_urlifier (lang_mask);
220 : : }
221 : :
222 : : #if CHECKING_P
223 : :
224 : : namespace selftest {
225 : :
226 : : /* Selftests. */
227 : :
228 : : /* Run all of the selftests within this file. */
229 : :
230 : : void
231 : 4 : gcc_urlifier_cc_tests ()
232 : : {
233 : : /* Check that doc_urls.quoted_text is sorted. */
234 : 68 : for (size_t idx = 1; idx < ARRAY_SIZE (doc_urls); idx++)
235 : 64 : gcc_assert (strcmp (doc_urls[idx - 1].quoted_text,
236 : : doc_urls[idx].quoted_text)
237 : : < 0);
238 : :
239 : 4 : gcc_urlifier u (0);
240 : :
241 : 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text ("").get (), nullptr);
242 : 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text (")").get (), nullptr);
243 : :
244 : 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("#pragma message").get (),
245 : : "gcc/Diagnostic-Pragmas.html");
246 : :
247 : : // Incomplete prefix of a quoted_text
248 : 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text ("#pragma mess").get (), nullptr);
249 : :
250 : : /* Check that every element is findable. */
251 : 72 : for (size_t idx = 0; idx < ARRAY_SIZE (doc_urls); idx++)
252 : 68 : ASSERT_STREQ
253 : : (u.get_url_suffix_for_quoted_text (doc_urls[idx].quoted_text).get (),
254 : : doc_urls[idx].url_suffix);
255 : :
256 : : /* Check an option. */
257 : 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("-fpack-struct").get (),
258 : : "gcc/Code-Gen-Options.html#index-fpack-struct");
259 : :
260 : : /* Check a "-fno-" variant of an option. */
261 : 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("-fno-inline").get (),
262 : : "gcc/Optimize-Options.html#index-finline");
263 : 4 : }
264 : :
265 : : } // namespace selftest
266 : :
267 : : #endif /* #if CHECKING_P */
|