示例#1
0
char *Reference_List (HText *text, BOOL titles)
{
    char *temp = malloc(1000);
    char *output = malloc(1000);
    int refs = HText_sourceAnchors(text);
    if (refs <= 0) {
        return("\n\nThere are no references from this document.\n\n");
    } else {
        int cnt;
        StrAllocCat(output,"\n*** References from this document ***\n");
        for (cnt=1; cnt<=refs; cnt++) {
            HTAnchor *dest =
                HTAnchor_followMainLink((HTAnchor *)
                                        HText_childNumber(text, cnt));
            HTParentAnchor * parent = HTAnchor_parent(dest);
            char * address =  HTAnchor_address(dest);
            const char * title = titles ? HTAnchor_title(parent) : NULL;
            sprintf(temp, "[%d] ", cnt);
            StrAllocCat(output, temp);
	    sprintf(temp, "%s\n",
                    (char *)(title ? title : address));
            StrAllocCat(output, temp);
            HT_FREE(address);
        }
    }
}      
示例#2
0
static void print_refs(FILE *fp, BOOLEAN titles, int refs)
{
    int cnt;
    char *address = NULL;
    const char *desc = gettext("unknown field or link");
    void *helper = NULL;	/* init */

    for (cnt = 1; cnt <= refs; cnt++) {
	HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
	HTAnchor *dest;
	HTParentAnchor *parent;
	const char *title;

	if (child == 0) {
	    /*
	     * child should not be 0 unless form field numbering is on and
	     * cnt is the number of a form input field. 
	     * HText_FormDescNumber() will set desc to a description of
	     * what type of input field this is.  We'll create a
	     * within-document link to ensure that the link numbers on the
	     * list page match the numbering in the original document, but
	     * won't create a forward link to the form.  - FM && LE
	     */
	    if (fields_are_numbered()) {
		HText_FormDescNumber(cnt, &desc);
		fprintf(fp, "%4d. form field = %s\n", cnt, desc);
	    }
	    continue;
	}
	dest = HTAnchor_followLink(child);
	/*
	 * Ignore if child anchor points to itself, i.e., we had something
	 * like <A NAME=xyz HREF="#xyz"> and it is not treated as a hidden
	 * link.  Useful if someone 'P'rints the List Page (which isn't a
	 * very useful action to do, but anyway...) - kw
	 */
	if (dest == (HTAnchor *) child)
	    continue;
	parent = HTAnchor_parent(dest);
	title = titles ? HTAnchor_title(parent) : NULL;
	address = HTAnchor_address(dest);
	fprintf(fp, "%4d. %s%s\n", cnt,
		((HTAnchor *) parent != dest) && title ? "in " : "",
		(title ? title : address));
	FREE(address);
#ifdef VMS
	if (HadVMSInterrupt)
	    break;
#endif /* VMS */
    }
}
示例#3
0
/*	Output the title line
**	---------------------
*/
PRIVATE void display_title (HText * text)
{
    const char * title = HTAnchor_title(text->node_anchor);
    char percent[20], format[20];
    if (text->lines > (DISPLAY_LINES-1)) {
#ifdef NOPE
	sprintf(percent, " (p%d of %d)",
	    (text->top_of_screen/(DISPLAY_LINES-1)) + 1,
	    (text->lines-1)/(DISPLAY_LINES-1) + 1);
	sprintf(percent, " (%d%%)",
	    100*(text->top_of_screen+DISPLAY_LINES-1)/	/* Seen */
	    	(text->lines));				/* Total */
#else
	sprintf(percent, " (%d/%d)",
	    text->top_of_screen+DISPLAY_LINES-1,	/* Seen */
	    text->lines);				/* Total */
#endif
    } else {
	percent[0] = 0;	/* Null string */
    }

    sprintf(format, "%%%d.%ds%%s\n",	/* Generate format string */
		    (int)(HTScreenWidth-strlen(percent)),
		    (int)(HTScreenWidth-strlen(percent)) );
#ifdef CURSES
    mvwprintw(w_top, 0, 0, format, title, percent);
    wrefresh(w_top);
#else
    if (!text->target) OutputData(LineMode_getView(text->pLm), format, title, percent);
    else {
    	char * line;
    	if ((line = (char *) HT_MALLOC(HTScreenWidth+10)) == NULL)
    	    HT_OUTOFMEM("display_titile");
        sprintf(line, format, title, percent);
	PUTS(line);
	HT_FREE(line);
    }
#endif
}
示例#4
0
PRIVATE void split_line (HText * text, int split)
{
    HTStyle * style = text->style;
    int spare;
    int indent = (int) (text->in_line_1 ? text->style->indent1st
			: text->style->leftIndent);

/*	Make new line
*/
    HTLine * previous = text->last_line;
    HTLine * line;
    if ((line = (HTLine  *) HT_MALLOC(LINE_SIZE(MAX_LINE))) == NULL)
        HT_OUTOFMEM("split_line");

    text->lines++;
    
    previous->next->prev = line;
    line->prev = previous;
    line->next = previous->next;
    previous->next = line;
    text->last_line = line;
    line->size = 0;
    line->offset = 0;

/*	Split at required point
*/    
    if (split) {	/* Delete space at "split" splitting line */
	char * p;
	previous->data[previous->size] = 0;
	for (p = &previous->data[split]; *p; p++)
	    if (*p != ' ') break;
	strcpy(line->data, p);
	line->size = strlen(line->data);
	previous->size = split;
    }
    
    while ((previous->size > 0) &&
	   (previous->data[previous->size-1] == ' '))	/* Strip trailers */
        previous->size--;

    if ((previous = (HTLine *)
	 HT_REALLOC(previous, LINE_SIZE(previous->size)))==NULL)
	HT_OUTOFMEM("split_line");
    previous->prev->next = previous;	/* Link in new line */
    previous->next->prev = previous;	/* Could be same node of course */

/*	Terminate finished line for printing
*/
    previous->data[previous->size] = 0;

/*	Align left, right or center
*/

    spare =  (int) (HTScreenWidth - style->rightIndent + style->leftIndent -
		    previous->size);		     /* @@ first line indent */
		
    switch (style->alignment) {
	case HT_CENTER :
	    previous->offset = previous->offset + indent + spare/2;
	    break;
	case HT_RIGHT :
	    previous->offset = previous->offset + indent + spare;
	    break;
	case HT_LEFT :
	case HT_JUSTIFY :		/* Not implemented */
	default:
	    previous->offset = previous->offset + indent;
	    break;
    } /* switch */

    text->chars = text->chars + previous->size + 1;	/* 1 for the line */
    text->in_line_1 = NO;		/* unless caller sets it otherwise */
    
/*	If displaying as we go, output it:
*/
    if (text->display_on_the_fly) {
        if (text->display_on_the_fly == DISPLAY_LINES) { /* First line */
	    if (previous->size == 0) {
	        text->top_of_screen++;	/* Scroll white space off top */
		return;
	    }
	    if (HTAnchor_title(text->node_anchor)) { /* Title exists */
	        display_title(text);
	        text->display_on_the_fly--;
	    }
	}
	display_line(text, previous);
	text->display_on_the_fly--;
	
	/* Loop to top of next page? */
	if (!text->display_on_the_fly && text->all_pages) {
	    PUTS("\f\n"); /* Form feed on its own line a la rfc1111 */
	    text->display_on_the_fly = DISPLAY_LINES;
	}
    }
} /* split_line */
示例#5
0
/*	Output a page
**	-------------
*/
PRIVATE void display_page (HText * text, int line_number)
{
    HTLine * line = text->last_line->prev;
    int i;
    const char * title = HTAnchor_title(text->node_anchor);
    int lines_of_text = title ? (DISPLAY_LINES-TITLE_LINES) : DISPLAY_LINES;
    int last_screen = text->lines - lines_of_text;

/*	Constrain the line number to be within the document
*/
    if (text->lines <= lines_of_text) line_number = 0;
    else if (line_number>last_screen) line_number = last_screen;
    else if (line_number < 0) line_number = 0;
    
    for(i=0,  line = text->last_line->next;		/* Find line */
    	i<line_number && (line!=text->last_line);
      i++, line=line->next) /* Loop */ assert(line->next != NULL);

    while((line!=text->last_line) && (line->size==0)) {	/* Skip blank lines */
        assert(line->next != NULL);
      line = line->next;
        line_number ++;
    }

/*	Can we just scroll to it?
*/ 
#ifndef VM			/* No scrolling */
    if (!text->stale && (line_number>=text->top_of_screen) &&
    	(line_number < text->top_of_screen + DISPLAY_LINES)) {	/* Yes */
	lines_of_text = line_number - text->top_of_screen;
	line = text->next_line;
        text->top_of_screen = line_number;
#ifdef CURSES
        scrollok(w_text, TRUE);
        for (i = 0; i < lines_of_text; i++) {
              scroll(w_text);
        }
#endif  
    } else
#endif
    {
	clear_screen();						/* No */
        text->top_of_screen = line_number;
	if (title) display_title(text);
    }
    
/* Bug: when we scroll to a part slightly futher down a page which previously
 fitted all on one screen including the [End], the code below will add an
 extra [End] to the screen, giving a total of two, one underneath the other.
*/
    
 /*	print it
 */
    if (line) {
      for(i=0;
	  (i< lines_of_text) && (line != text->last_line); i++)  {
      assert(line != NULL);
        display_line(text, line);
	line = line->next;
      }
      fill_screen(text, lines_of_text - i);
    }

    text->next_line = line;	/* Line after screen */
    text->stale = NO;		/* Display is up-to-date */
}
示例#6
0
PRIVATE void parse_menu ARGS2 (
                               CONST char *,	arg,
                               HTParentAnchor *,anAnchor)
{
  char gtype;
  char ch;
  char line[BIG];
  char address[BIG];
  char *name, *selector;		/* Gopher menu fields */
  char *host;
  char *port;
  char *p = line;
  
  
#define TAB 		'\t'
#define HEX_ESCAPE 	'%'
  
  if (!HTAnchor_title(anAnchor))
    HTAnchor_setTitle(anAnchor, arg);/* Tell user something's happening */
  
  node_anchor = anAnchor;
  HT = HText_new(anAnchor);
  
  HText_beginAppend(HT);
  HText_appendText(HT, "Select one of:<P>\n<UL>");
  /* HText_appendText(HT, "Select one of:<P>\n<UL>"); */
  
  while ((ch=NEXT_CHAR) != (char)EOF) 
    {
      if (ch != '\n') 
        {
          *p = ch;		/* Put character in line */
          if (p< &line[BIG-1]) p++;
        } 
      else 
        {
          *p++ = 0;		/* Terminate line */
          p = line;		/* Scan it to parse it */
          port = 0;		/* Flag "not parsed" */
          if (TRACE) fprintf(stderr, "HTGopher: Menu item: %s\n", line);
          gtype = *p++;
          
          /* Break on line with a dot by itself */
          if ((gtype=='.') && ((*p=='\r') || (*p==0))) break;
          
          if (gtype && *p) 
            {
              name = p;
              selector = strchr(name, TAB);
              if (selector) {
                *selector++ = 0;	/* Terminate name */
                host = strchr(selector, TAB);
                if (host) {
                  *host++ = 0;	/* Terminate selector */
                  port = strchr(host, TAB);
                  if (port) {
                    char *junk;
                    port[0] = ':';	/* delimit host a la W3 */
                    junk = strchr(port, 13 /* was TAB */);
                    if (junk) *junk++ = 0;	/* Chop port */
                    if ((port[1]=='0') && (!port[2]))
                      port[0] = 0;	/* 0 means none */
                  } /* no port */
                } /* host ok */
              } /* selector ok */
            } /* gtype and name ok */
          
          if (gtype == GOPHER_WWW) 
            {	/* Gopher pointer to W3 */
              HText_appendText(HT, "<LI> ");
              write_anchor(name, selector);
              HText_appendText(HT, "\n");
              /* HText_appendParagraph(HT); */
            } 
          else if (port) 
            {		/* Other types need port */
              if (gtype == GOPHER_TELNET) 
                {
                  if (*selector) 
                    sprintf(address, "telnet://%s@%s/",
                            selector, host);
                  else 
                    sprintf(address, "telnet://%s/", host);
                }
              else if (gtype == GOPHER_TN3270) 
                {
                  if (*selector) 
                    sprintf(address, "tn3270://%s@%s/",
                            selector, host);
                  else 
                    sprintf(address, "tn3270://%s/", host);
                }
              else 
                {			/* If parsed ok */
                  char *q;
                  char *p;
                  sprintf(address, "gopher://%s/%c", host, gtype);
                  q = address+ strlen(address);
                  for(p=selector; *p; p++) {	/* Encode selector string */
                    /* fprintf (stderr, "Checking %d (%c) for acceptable.\n",
                     *p, *p); */
                    if (acceptable[*p]) *q++ = *p;
                    else {
                      *q++ = HEX_ESCAPE;	/* Means hex coming */
                      *q++ = hex[(TOASCII(*p)) >> 4];
                      *q++ = hex[(TOASCII(*p)) & 15];
                    }
                  }
                  *q++ = 0;			/* terminate address */
                }
              /* HText_appendText(HT, "        "); */ /* Prettier JW/TBL */
              HText_appendText(HT, "<LI> ");
              /* Error response from Gopher doesn't deserve to
                 be a hyperlink. */
              if (strcmp (address, "gopher://error.host:1/0"))
                write_anchor(name, address);
              else
                HText_appendText(HT, name);
              HText_appendText(HT, "\n");
              /* HText_appendParagraph(HT); */
            } 
          else 
            { /* parse error */
              if (TRACE) fprintf(stderr,
                                 "HTGopher: Bad menu item.\n");
              HText_appendText(HT, line);
              HText_appendParagraph(HT);
            } /* parse error */
          
          p = line;	/* Start again at beginning of line */
          
        } /* if end of line */
      
    } /* Loop over characters */
示例#7
0
PRIVATE void HTML_start_element (HTStructured *	me,
				 int		element_number,
				 const BOOL * 	present,
				 const char **	value)
{
    HTChildAnchor * address = NULL;
    if (!me->started) {
	HTextImp_build(me->text, HTEXT_BEGIN);
	me->started = YES;
    }

    /* Look at what element was started */
    switch (element_number) {
    case HTML_A:
	if (present[HTML_A_HREF] && value[HTML_A_HREF]) {
	    address = HTAnchor_findChildAndLink(
		me->node_anchor,					/* parent */
		present[HTML_A_NAME] ? value[HTML_A_NAME] : NULL,	/* Tag */
		value[HTML_A_HREF],					/* Addresss */
		present[HTML_A_REL] && value[HTML_A_REL] ? 
		(HTLinkType) HTAtom_caseFor(value[HTML_A_REL]) : NULL);
	    
	    if (present[HTML_A_TITLE] && value[HTML_A_TITLE]) {
		HTLink * link = HTAnchor_mainLink((HTAnchor *) address);
		HTParentAnchor * dest = HTAnchor_parent(HTLink_destination(link));
		if (!HTAnchor_title(dest)) HTAnchor_setTitle(dest, value[HTML_A_TITLE]);
	    }
	    HTextImp_foundLink(me->text, element_number, HTML_A_HREF,
			       address, present, value);
	    HTTRACE(SGML_TRACE, "HTML Parser. Anchor `%s\'\n" _ value[HTML_A_HREF]);
	}
	break;

    case HTML_AREA:
	if (present[HTML_AREA_HREF] && value[HTML_AREA_HREF]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_AREA_HREF], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_AREA_HREF,
			       address, present, value);
	    HTTRACE(SGML_TRACE, "HTML Parser. Image map area `%s\'\n" _ value[HTML_AREA_HREF]);
	}
	break;

    case HTML_BASE:
	if (present[HTML_BASE_HREF] && value[HTML_BASE_HREF]) {
	    HTAnchor_setBase(me->node_anchor, (char *) value[HTML_BASE_HREF]);
	    HTTRACE(SGML_TRACE, "HTML Parser. New base `%s\'\n" _ value[HTML_BASE_HREF]);
	}
	break;

    case HTML_BODY:
	if (present[HTML_BODY_BACKGROUND] && value[HTML_BODY_BACKGROUND]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_BODY_BACKGROUND], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_BODY_BACKGROUND,
			       address, present, value);
	    HTTRACE(SGML_TRACE, "HTML Parser. Background `%s\'\n" _ value[HTML_BODY_BACKGROUND]);
	}
	break;

    case HTML_FORM:
	if (present[HTML_FORM_ACTION] && value[HTML_FORM_ACTION]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_FORM_ACTION], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_FORM_ACTION,
			       address, present, value);
	}
	break;

    case HTML_FRAME:
	if (present[HTML_FRAME_SRC] && value[HTML_FRAME_SRC]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_FRAME_SRC], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_FRAME_SRC,
			       address, present, value);
	    HTTRACE(SGML_TRACE, "HTML Parser. Frame `%s\'\n" _ value[HTML_FRAME_SRC]);
	}
	break;
	
    case HTML_INPUT:
	if (present[HTML_INPUT_SRC] && value[HTML_INPUT_SRC]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_INPUT_SRC], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_INPUT_SRC,
			       address, present, value);
	}
	break;

    case HTML_IMG:
	if (present[HTML_IMG_SRC] && value[HTML_IMG_SRC]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_IMG_SRC], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_IMG_SRC,
			       address, present, value);
	}
	break;

    case HTML_ISINDEX:
   	HTAnchor_setIndex(me->node_anchor);
	break;
	
    case HTML_LINK:
	if (present[HTML_LINK_HREF] && value[HTML_LINK_HREF]) {
	    HTParentAnchor * dest = NULL;
	    address = HTAnchor_findChildAndLink(
		me->node_anchor,					/* parent */
		present[HTML_A_NAME] ? value[HTML_A_NAME] : NULL,	/* Tag */
		present[HTML_A_HREF] ? value[HTML_A_HREF] : NULL,	/* Addresss */
		NULL);							/* Rels */
	    dest = HTAnchor_parent(HTAnchor_followMainLink((HTAnchor *) address));

	    /* If forward reference */
	    if ((present[HTML_LINK_REL] && value[HTML_LINK_REL])) {
		char * strval = NULL;
		char * ptr = NULL;
		char * relation = NULL;
		StrAllocCopy(strval, value[HTML_LINK_REL]);
		ptr = strval;
		while ((relation = HTNextLWSToken(&ptr)) != NULL) {
		    HTLink_add((HTAnchor *) me->node_anchor, (HTAnchor *) dest,
			       (HTLinkType) HTAtom_caseFor(relation),
			       METHOD_INVALID);
		}
		HT_FREE(strval);
	    }

	    /* If reverse reference */
	    if ((present[HTML_LINK_REV] && value[HTML_LINK_REV])) {
		char * strval = NULL;
		char * ptr = NULL;
		char * relation = NULL;
		StrAllocCopy(strval, value[HTML_LINK_REV]);
		ptr = strval;
		while ((relation = HTNextLWSToken(&ptr)) != NULL) {
		    HTLink_add((HTAnchor *) dest, (HTAnchor *) me->node_anchor,
			       (HTLinkType) HTAtom_caseFor(relation),
			       METHOD_INVALID);
		}
		HT_FREE(strval);
	    }

	    /* If we got any type information as well */
	    if (present[HTML_LINK_TYPE] && value[HTML_LINK_TYPE]) {
		if (HTAnchor_format(dest) == WWW_UNKNOWN)
		    HTAnchor_setFormat(dest,
				       (HTFormat) HTAtom_caseFor(value[HTML_LINK_TYPE]));
	    }

	    /* Call out to the layout engine */
	    HTextImp_foundLink(me->text, element_number, HTML_LINK_HREF,
			       address, present, value);
	}
	break;

    case HTML_META:
	if (present[HTML_META_NAME] && value[HTML_META_NAME]) {
	    HTAnchor_addMeta (me->node_anchor,
			      value[HTML_META_NAME],
			      (present[HTML_META_CONTENT] && value[HTML_META_CONTENT]) ?
			      value[HTML_META_CONTENT] : "");
	}
	break;

    case HTML_OBJECT:
	if (present[HTML_OBJECT_CLASSID] && value[HTML_OBJECT_CLASSID]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_OBJECT_CLASSID], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_OBJECT_CLASSID,
			       address, present, value);
	}

	if (present[HTML_OBJECT_CODEBASE] && value[HTML_OBJECT_CODEBASE]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_OBJECT_CODEBASE], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_OBJECT_CODEBASE,
			       address, present, value);
	}

	if (present[HTML_OBJECT_DATA] && value[HTML_OBJECT_DATA]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_OBJECT_DATA], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_OBJECT_DATA,
			       address, present, value);
	}

	if (present[HTML_OBJECT_ARCHIVE] && value[HTML_OBJECT_ARCHIVE]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_OBJECT_ARCHIVE], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_OBJECT_ARCHIVE,
			       address, present, value);
	}

	if (present[HTML_OBJECT_USEMAP] && value[HTML_OBJECT_USEMAP]) {
	    address = HTAnchor_findChildAndLink(me->node_anchor, NULL,
						value[HTML_OBJECT_USEMAP], NULL);
	    HTextImp_foundLink(me->text, element_number, HTML_OBJECT_USEMAP,
			       address, present, value);
	}
	break;

    case HTML_PRE:
    	if (me->comment_end)
	    HTextImp_addText(me->text, me->comment_end, strlen(me->comment_end));
	break;

    case HTML_TITLE:
        HTChunk_truncate(me->title,0);
	break;
    }

    /* Update our parse stack */
    if (SGML_findTagContents(me->dtd, element_number) != SGML_EMPTY) {
        if (me->sp == me->stack) {
	    HTTRACE(SGML_TRACE, "HTML Parser. Maximum nesting of %d exceded!\n" _ MAX_NESTING); 
	    me->overflow++;
	    return;
	}
    	--(me->sp);
	me->sp[0] = element_number;
    }	

    /* Call out to the layout engine */
    HTextImp_beginElement(me->text, element_number, present, value);
}
示例#8
0
int showlist(DocInfo *newdoc, BOOLEAN titles)
{
    int cnt;
    int refs, hidden_links;
    static char tempfile[LY_MAXPATH];
    static BOOLEAN last_titles = TRUE;
    FILE *fp0;
    char *Address = NULL, *Title = NULL, *cp = NULL;
    char *LinkTitle = NULL;	/* Rel stored as property of link, not of dest */
    BOOLEAN intern_w_post = FALSE;
    const char *desc = "unknown field or link";
    void *helper;

    refs = HText_sourceAnchors(HTMainText);
    hidden_links = HText_HiddenLinkCount(HTMainText);
    if (refs <= 0 && hidden_links > 0 &&
	LYHiddenLinks != HIDDENLINKS_SEPARATE) {
	HTUserMsg(NO_VISIBLE_REFS_FROM_DOC);
	return (-1);
    }
    if (refs <= 0 && hidden_links <= 0) {
	HTUserMsg(NO_REFS_FROM_DOC);
	return (-1);
    }

    if ((fp0 = InternalPageFP(tempfile, titles == last_titles)) == 0)
	return (-1);

    LYLocalFileToURL(&(newdoc->address), tempfile);

    LYRegisterUIPage(newdoc->address,
		     titles ? UIP_LIST_PAGE : UIP_ADDRLIST_PAGE);
    last_titles = titles;
    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
    LYforce_no_cache = TRUE;	/* force this file to be new */

#ifdef EXP_ADDRLIST_PAGE
    if (titles != TRUE)
	BeginInternalPage(fp0, ADDRLIST_PAGE_TITLE, LIST_PAGE_HELP);
    else
#endif
	BeginInternalPage(fp0, LIST_PAGE_TITLE, LIST_PAGE_HELP);

    StrAllocCopy(Address, HTLoadedDocumentURL());
    LYEntify(&Address, FALSE);
    fprintf(fp0, "%s%s<p>\n", gettext("References in "),
	    (non_empty(Address)
	     ? Address
	     : gettext("this document:")));
    FREE(Address);
    if (refs > 0) {
	fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
					"ol" : "ul"));
	if (hidden_links > 0)
	    fprintf(fp0, "<lh><em>%s</em>\n", gettext("Visible links:"));
    }
    if (hidden_links > 0) {
	if (LYHiddenLinks == HIDDENLINKS_IGNORE)
	    hidden_links = 0;
    }
    helper = NULL;		/* init */
    for (cnt = 1; cnt <= refs; cnt++) {
	HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
	HTAnchor *dest_intl = NULL;
	HTAnchor *dest;
	HTParentAnchor *parent;
	char *address;
	const char *title;

	if (child == 0) {
	    /*
	     * child should not be 0 unless form field numbering is on and cnt
	     * is the number of a form input field.  HText_FormDescNumber()
	     * will set desc to a description of what type of input field this
	     * is.  We'll list it to ensure that the link numbers on the list
	     * page match the numbering in the original document, but won't
	     * create a forward link to the form.  - FM && LE
	     *
	     * Changed to create a fake hidden link, to get the numbering right
	     * in connection with always treating this file as
	     * HIDDENLINKS_MERGE in GridText.c - kw
	     */
	    if (fields_are_numbered()) {
		HText_FormDescNumber(cnt, &desc);
		fprintf(fp0,
			"<li><a id=%d href=\"#%d\">form field</a> = <em>%s</em>\n",
			cnt, cnt, desc);
	    }
	    continue;
	}
#ifndef DONT_TRACK_INTERNAL_LINKS
	dest_intl = HTAnchor_followTypedLink(child, HTInternalLink);
#endif
	dest = dest_intl ?
	    dest_intl : HTAnchor_followLink(child);
	parent = HTAnchor_parent(dest);
	if (!intern_w_post && dest_intl &&
	    HTMainAnchor &&
	    HTMainAnchor->post_data &&
	    parent->post_data &&
	    BINEQ(HTMainAnchor->post_data, parent->post_data)) {
	    /*
	     * Set flag to note that we had at least one internal link, if the
	     * document from which we are generating the list has associated
	     * POST data; after an extra check that the link destination really
	     * has the same POST data so that we can believe it is an internal
	     * link.
	     */
	    intern_w_post = TRUE;
	}
	address = HTAnchor_address(dest);
	title = titles ? HTAnchor_title(parent) : NULL;
	if (dest_intl) {
	    HTSprintf0(&LinkTitle, "(internal)");
	} else if (titles && child->type &&
		   dest == child->dest &&
		   !strncmp(HTAtom_name(child->type),
			    "RelTitle: ", 10)) {
	    HTSprintf0(&LinkTitle, "(%s)", HTAtom_name(child->type) + 10);
	} else {
	    FREE(LinkTitle);
	}
	StrAllocCopy(Address, address);
	FREE(address);
	LYEntify(&Address, TRUE);
	if (non_empty(title)) {
	    LYformTitle(&Title, title);
	    LYEntify(&Title, TRUE);
	    if (*Title) {
		cp = findPoundSelector(Address);
	    } else {
		FREE(Title);
	    }
	}

	fprintf(fp0, "<li><a href=\"%s\"%s>%s%s%s%s%s</a>\n", Address,
		dest_intl ? " TYPE=\"internal link\"" : "",
		NonNull(LinkTitle),
		((HTAnchor *) parent != dest) && Title ? "in " : "",
		(char *) (Title ? Title : Address),
		(Title && cp) ? " - " : "",
		(Title && cp) ? (cp + 1) : "");

	FREE(Address);
	FREE(Title);
    }
    FREE(LinkTitle);

    if (hidden_links > 0) {
	if (refs > 0)
	    fprintf(fp0, "\n</%s>\n\n<p>\n",
		    ((keypad_mode == NUMBERS_AS_ARROWS) ?
		     "ol" : "ul"));
	fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
					"ol continue" : "ul"));
	fprintf(fp0, "<lh><em>%s</em>\n", gettext("Hidden links:"));
    }

    for (cnt = 0; cnt < hidden_links; cnt++) {
	StrAllocCopy(Address, HText_HiddenLinkAt(HTMainText, cnt));
	LYEntify(&Address, FALSE);
	if (isEmpty(Address)) {
	    FREE(Address);
	    continue;
	}
	fprintf(fp0, "<li><a href=\"%s\">%s</a>\n", Address, Address);

	FREE(Address);
    }

    fprintf(fp0, "\n</%s>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
			       "ol" : "ul"));
    EndInternalPage(fp0);
    LYCloseTempFP(fp0);

    /*
     * Make necessary changes to newdoc before returning to caller.  If the
     * intern_w_post flag is set, we keep the POST data in newdoc that have
     * been passed in.  They should be the same as in the loaded document for
     * which we generated the list.  In that case the file we have written will
     * be associated with the same POST data when it is loaded after we are
     * done here, so that following one of the links we have marked as
     * "internal link" can lead back to the underlying document with the right
     * address+post_data combination.  - kw
     */
    if (intern_w_post) {
	newdoc->internal_link = TRUE;
    } else {
	LYFreePostData(newdoc);
	newdoc->internal_link = FALSE;
    }
    newdoc->isHEAD = FALSE;
    newdoc->safe = FALSE;
    return (0);
}