1 /*
2 * $LynxId: LYList.c,v 1.55 2020/02/23 21:20:05 tom Exp $
3 *
4 * Lynx Document Reference List Support LYList.c
5 * ====================================
6 *
7 * Author: FM Foteos Macrides (macrides@sci.wfbr.edu)
8 *
9 */
10
11 #include <HTUtils.h>
12 #include <HTAlert.h>
13 #include <LYUtils.h>
14 #include <GridText.h>
15 #include <HTParse.h>
16 #include <LYList.h>
17 #include <LYMap.h>
18 #include <LYClean.h>
19 #include <LYGlobalDefs.h>
20 #include <LYCharUtils.h>
21 #include <LYCharSets.h>
22 #include <LYStrings.h>
23 #include <LYHistory.h>
24
25 #ifdef DIRED_SUPPORT
26 #include <LYUpload.h>
27 #include <LYLocal.h>
28 #endif /* DIRED_SUPPORT */
29
30 #include <LYexit.h>
31 #include <LYLeaks.h>
32
33 /* showlist - F.Macrides (macrides@sci.wfeb.edu)
34 * --------
35 * Create a temporary text/html file with a list of links to
36 * HyperText References in the current document.
37 *
38 * On entry
39 * titles Set: if we want titles where available
40 * Clear: we only get addresses.
41 */
42
showlist(DocInfo * newdoc,int titles)43 int showlist(DocInfo *newdoc, int titles)
44 {
45 int cnt;
46 int refs, hidden_links;
47 int result;
48 static char tempfile[LY_MAXPATH];
49 static BOOLEAN last_titles = TRUE;
50 FILE *fp0;
51 char *Address = NULL, *Title = NULL, *cp = NULL;
52 char *LinkTitle = NULL; /* Rel stored as property of link, not of dest */
53 BOOLEAN intern_w_post = FALSE;
54 const char *desc = "unknown field or link";
55 void *helper;
56
57 refs = HText_sourceAnchors(HTMainText);
58 hidden_links = HText_HiddenLinkCount(HTMainText);
59 if (refs <= 0 && hidden_links > 0 &&
60 LYHiddenLinks != HIDDENLINKS_SEPARATE) {
61 HTUserMsg(NO_VISIBLE_REFS_FROM_DOC);
62 return (-1);
63 }
64 if (refs <= 0 && hidden_links <= 0) {
65 HTUserMsg(NO_REFS_FROM_DOC);
66 return (-1);
67 }
68
69 if ((fp0 = InternalPageFP(tempfile, titles == last_titles)) == 0)
70 return (-1);
71
72 LYLocalFileToURL(&(newdoc->address), tempfile);
73
74 LYRegisterUIPage(newdoc->address,
75 titles ? UIP_LIST_PAGE : UIP_ADDRLIST_PAGE);
76 last_titles = (BOOLEAN) titles;
77 LYforce_HTML_mode = TRUE; /* force this file to be HTML */
78 LYforce_no_cache = TRUE; /* force this file to be new */
79
80 #ifdef USE_ADDRLIST_PAGE
81 if (titles != TRUE)
82 BeginInternalPage(fp0, ADDRLIST_PAGE_TITLE, LIST_PAGE_HELP);
83 else
84 #endif
85 BeginInternalPage(fp0, LIST_PAGE_TITLE, LIST_PAGE_HELP);
86
87 StrAllocCopy(Address, HTLoadedDocumentURL());
88 LYEntify(&Address, FALSE);
89 fprintf(fp0, "%s%s<p>\n", gettext("References in "),
90 (non_empty(Address)
91 ? Address
92 : gettext("this document:")));
93 FREE(Address);
94 if (refs > 0) {
95 fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
96 "ol" : "ul"));
97 if (hidden_links > 0)
98 fprintf(fp0, "<lh><em>%s</em>\n", gettext("Visible links:"));
99 }
100 if (hidden_links > 0) {
101 if (LYHiddenLinks == HIDDENLINKS_IGNORE)
102 hidden_links = 0;
103 }
104 helper = NULL; /* init */
105 result = 1;
106 for (cnt = 1; cnt <= refs; cnt++) {
107 HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
108 int value = HText_findAnchorNumber(helper);
109 HTAnchor *dest_intl = NULL;
110 HTAnchor *dest;
111 HTParentAnchor *parent;
112 char *address;
113 const char *title;
114
115 if (child == 0) {
116 /*
117 * child should not be 0 unless form field numbering is on and cnt
118 * is the number of a form input field. HText_FormDescNumber()
119 * will set desc to a description of what type of input field this
120 * is. We'll list it to ensure that the link numbers on the list
121 * page match the numbering in the original document, but won't
122 * create a forward link to the form. - FM && LE
123 *
124 * Changed to create a fake hidden link, to get the numbering right
125 * in connection with always treating this file as
126 * HIDDENLINKS_MERGE in GridText.c - kw
127 */
128 if (fields_are_numbered()) {
129 HText_FormDescNumber(cnt, &desc);
130 fprintf(fp0,
131 "<li><a id=%d href=\"#%d\">form field</a> = <em>%s</em>\n",
132 cnt, cnt, desc);
133 }
134 } else if (value >= result) {
135 if (track_internal_links)
136 dest_intl = HTAnchor_followTypedLink(child, HTInternalLink);
137 dest = (dest_intl
138 ? dest_intl
139 : HTAnchor_followLink(child));
140 parent = HTAnchor_parent(dest);
141 if (!intern_w_post && dest_intl &&
142 HTMainAnchor &&
143 HTMainAnchor->post_data &&
144 parent->post_data &&
145 BINEQ(HTMainAnchor->post_data, parent->post_data)) {
146 /*
147 * Set flag to note that we had at least one internal link, if
148 * the document from which we are generating the list has
149 * associated POST data; after an extra check that the link
150 * destination really has the same POST data so that we can
151 * believe it is an internal link.
152 */
153 intern_w_post = TRUE;
154 }
155 address = HTAnchor_address(dest);
156 title = titles ? HTAnchor_title(parent) : NULL;
157 if (dest_intl) {
158 HTSprintf0(&LinkTitle, "(internal)");
159 } else if (titles && child->type &&
160 dest == child->dest &&
161 !StrNCmp(HTAtom_name(child->type),
162 "RelTitle: ", 10)) {
163 HTSprintf0(&LinkTitle, "(%s)", HTAtom_name(child->type) + 10);
164 } else {
165 FREE(LinkTitle);
166 }
167 StrAllocCopy(Address, address);
168 FREE(address);
169 LYEntify(&Address, TRUE);
170 if (non_empty(title)) {
171 LYformTitle(&Title, title);
172 LYEntify(&Title, TRUE);
173 if (*Title) {
174 cp = findPoundSelector(Address);
175 } else {
176 FREE(Title);
177 }
178 }
179
180 fprintf(fp0, "<li><a href=\"%s\"%s>%s%s%s%s%s</a>\n", Address,
181 dest_intl ? " TYPE=\"internal link\"" : "",
182 NonNull(LinkTitle),
183 ((HTAnchor *) parent != dest) && Title ? "in " : "",
184 (char *) (Title ? Title : Address),
185 (Title && cp) ? " - " : "",
186 (Title && cp) ? (cp + 1) : "");
187
188 FREE(Address);
189 FREE(Title);
190 }
191 result = value + 1;
192 }
193 FREE(LinkTitle);
194
195 if (hidden_links > 0) {
196 if (refs > 0)
197 fprintf(fp0, "\n</%s>\n\n<p>\n",
198 ((keypad_mode == NUMBERS_AS_ARROWS) ?
199 "ol" : "ul"));
200 fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
201 "ol continue" : "ul"));
202 fprintf(fp0, "<lh><em>%s</em>\n", gettext("Hidden links:"));
203 }
204
205 for (cnt = 0; cnt < hidden_links; cnt++) {
206 StrAllocCopy(Address, HText_HiddenLinkAt(HTMainText, cnt));
207 LYEntify(&Address, FALSE);
208 if (isEmpty(Address)) {
209 FREE(Address);
210 continue;
211 }
212 fprintf(fp0, "<li><a href=\"%s\">%s</a>\n", Address, Address);
213
214 FREE(Address);
215 }
216
217 fprintf(fp0, "\n</%s>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
218 "ol" : "ul"));
219 EndInternalPage(fp0);
220 LYCloseTempFP(fp0);
221
222 /*
223 * Make necessary changes to newdoc before returning to caller. If the
224 * intern_w_post flag is set, we keep the POST data in newdoc that have
225 * been passed in. They should be the same as in the loaded document for
226 * which we generated the list. In that case the file we have written will
227 * be associated with the same POST data when it is loaded after we are
228 * done here, so that following one of the links we have marked as
229 * "internal link" can lead back to the underlying document with the right
230 * address+post_data combination. - kw
231 */
232 if (intern_w_post) {
233 newdoc->internal_link = TRUE;
234 } else {
235 LYFreePostData(newdoc);
236 newdoc->internal_link = FALSE;
237 }
238 newdoc->isHEAD = FALSE;
239 newdoc->safe = FALSE;
240 return (0);
241 }
242
print_refs(FILE * fp,int titles,int refs)243 static int print_refs(FILE *fp, int titles, int refs)
244 {
245 int result = 0;
246 int cnt;
247 int value;
248 char *address = NULL;
249 const char *desc = gettext("unknown field or link");
250 void *helper = NULL; /* init */
251
252 for (cnt = 1; cnt <= refs; cnt++) {
253 HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
254 HTAnchor *dest;
255 HTParentAnchor *parent;
256 const char *title;
257 int counter = result + 1;
258
259 if (child == 0) {
260 /*
261 * child should not be 0 unless form field numbering is on and
262 * cnt is the number of a form input field.
263 * HText_FormDescNumber() will set desc to a description of
264 * what type of input field this is. We'll create a
265 * within-document link to ensure that the link numbers on the
266 * list page match the numbering in the original document, but
267 * won't create a forward link to the form. - FM && LE
268 */
269 if (fields_are_numbered()) {
270 HText_FormDescNumber(cnt, &desc);
271 fprintf(fp, "%4d. form field = %s\n", counter, desc);
272 }
273 } else {
274 dest = HTAnchor_followLink(child);
275 /*
276 * Ignore if child anchor points to itself, i.e., we had something
277 * like <A NAME=xyz HREF="#xyz"> and it is not treated as a hidden
278 * link. Useful if someone 'P'rints the List Page (which isn't a
279 * very useful action to do, but anyway...) - kw
280 */
281 if (dest != (HTAnchor *) child) {
282 parent = HTAnchor_parent(dest);
283 title = titles ? HTAnchor_title(parent) : NULL;
284 if (links_are_numbered()) {
285 value = HText_findAnchorNumber(helper);
286 if (value <= result)
287 continue;
288 fprintf(fp, "%4d. ", value);
289 }
290 if (((HTAnchor *) parent != dest) && title) {
291 fprintf(fp, "in ");
292 }
293 if (title) {
294 fprintf(fp, "%s\n", title);
295 } else {
296 address = HTAnchor_short_address(dest);
297 if (dump_links_decoded
298 && LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
299 (void) HTUnEscape(address);
300 }
301 fprintf(fp, "%s\n", address);
302 FREE(address);
303 }
304 }
305 }
306 if (counter > result)
307 result = counter;
308 #ifdef VMS
309 if (HadVMSInterrupt)
310 break;
311 #endif /* VMS */
312 }
313 return result;
314 }
315
print_hidden_refs(FILE * fp,int refs,int hidden_links)316 static void print_hidden_refs(FILE *fp, int refs, int hidden_links)
317 {
318 int cnt;
319 char *address = NULL;
320
321 fprintf(fp, "%s %s\n", ((refs > 0) ? "\n" : ""),
322 gettext("Hidden links:"));
323 for (cnt = 0; cnt < hidden_links; cnt++) {
324 StrAllocCopy(address, HText_HiddenLinkAt(HTMainText, cnt));
325 if (isEmpty(address)) {
326 FREE(address);
327 continue;
328 }
329
330 if (links_are_numbered())
331 fprintf(fp, "%4d. ", ((cnt + 1) + refs));
332 fprintf(fp, "%s\n", address);
333 FREE(address);
334 #ifdef VMS
335 if (HadVMSInterrupt)
336 break;
337 #endif /* VMS */
338 }
339 }
340
341 /* printlist - F.Macrides (macrides@sci.wfeb.edu)
342 * ---------
343 * Print a text/plain list of HyperText References
344 * in the current document.
345 *
346 * On entry
347 * titles Set: if we want titles where available
348 * Clear: we only get addresses.
349 */
printlist(FILE * fp,int titles)350 void printlist(FILE *fp, int titles)
351 {
352 int refs, hidden_links;
353
354 refs = HText_sourceAnchors(HTMainText);
355 if (refs > 0 || LYHiddenLinks == HIDDENLINKS_SEPARATE) {
356 hidden_links = HText_HiddenLinkCount(HTMainText);
357 if (refs > 0 || hidden_links > 0) {
358 if (links_are_numbered() || fields_are_numbered())
359 fprintf(fp, "\n%s\n\n", gettext("References"));
360 if (LYHiddenLinks == HIDDENLINKS_IGNORE)
361 hidden_links = 0;
362 if (hidden_links > 0) {
363 fprintf(fp, " %s\n", gettext("Visible links:"));
364 }
365 refs = print_refs(fp, titles, refs) + 1;
366
367 if (hidden_links > 0) {
368 print_hidden_refs(fp, refs, hidden_links);
369 }
370 }
371 }
372 LYPrintImgMaps(fp);
373 return;
374 }
375