summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdvik/hypertex.c
diff options
context:
space:
mode:
authorDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
committerDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
commitc6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch)
tree1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/xdvik/hypertex.c
parent07ee7222e389b0777456b427a55c22d0e6ffd267 (diff)
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvik/hypertex.c')
-rw-r--r--Build/source/texk/xdvik/hypertex.c2257
1 files changed, 0 insertions, 2257 deletions
diff --git a/Build/source/texk/xdvik/hypertex.c b/Build/source/texk/xdvik/hypertex.c
deleted file mode 100644
index 2cb55d07406..00000000000
--- a/Build/source/texk/xdvik/hypertex.c
+++ /dev/null
@@ -1,2257 +0,0 @@
-
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * Original copyright:
- *
- * Hypertex modifications to DVI previewer for X.
- * This portion of xhdvi is completely in the public domain. The
- * author renounces any copyright claims. It may be freely used for
- * commercial or non-commercial purposes. The author makes no claims
- * or guarantees - use this at your own risk.
- *
- * Arthur Smith, U. of Washington, 1994
- *
- * 5/1994 code written from scratch, probably inspired by (but
- * incompatible with) the CERN WWW library.
- *
- * 3/1995 CERN WWW library called to do document fetching.
- *
- * 5/2002 SU: rewritten from scratch to make it work with the new
- * event handling in xdvi >= 22.41: Anchors are now saved
- * per page instead of per document, making it more robust
- * wrt. interrupting the drawing and skipping to another page.
- * Only drawback is that links breaking over pages are more
- * difficult to handle (but they didn't work properly before either).
- * Clicking on a link now performs a search for the
- * corresponding anchor similiar to `forward search'.
- *
- * Removed libwww, since it has become too bloated
- * and buggy, and had only rudimentary support for GUI
- * interaction to begin with (e.g., interrupting a
- * download). And since this is 2002, we might just as well
- * use a web browser to fetch remote documents ;-)
- */
-
-/* TODO:
-
-- implement popup with list of visited links, as specified in
-http://xdvi.sourceforge.net/gui.html#navigation-openLinks
-(maybe this should be a simple menu list, not a popup window).
-*/
-
-#define COPY_TMP_FILE 0 /* see comments below */
-
-#include "xdvi-config.h"
-#include "xdvi.h"
-
- /* #define DEBUG */
-
- /* #define DEBUG_MEMORY_HANDLING */
-#include "alloc-debug.h"
-
-#include <string.h>
-
-#include <ctype.h>
-#include "kpathsea/c-fopen.h"
-#include "kpathsea/c-stat.h"
-#include <X11/StringDefs.h> /* for XtNwidth, XtNheight */
-
-#include "events.h"
-#include "dvi-init.h"
-#include "message-window.h"
-#include "util.h"
-#include "dl_list.h"
-#include "x_util.h"
-#include "mime.h"
-#include "mag.h"
-#include "dvi-draw.h"
-#include "statusline.h"
-#include "browser.h"
-#include "hypertex.h"
-#include "special.h"
-#include "string-utils.h"
-#include "xm_toolbar.h"
-#include "my-snprintf.h"
-#include "pagehist.h"
-
- /* globals */
- /* rgb specifications to translate resource.{visited_}link_color into */
- char *g_link_color_rgb = NULL;
-char *g_visited_link_color_rgb = NULL;
-char *g_anchor_pos = NULL;
-size_t g_anchor_len = 0;
-
-static const int DEFAULT_MARKER_X_OFFSET = 2; /* horizontal offset of anchor marker to edge of screen */
-static const int HTEX_ALLOC_STEP = 32;
-
-/* distance of underline from lower edge of character bbox */
-static const int ANCHOR_XTRA_V_BBOX = 6;
-
-/* info whether we're dealing with hypertex or hdvips type links */
-typedef enum { HYPERTEX_LINK, HDVIPS_LINK } hrefLinkT;
-static hrefLinkT m_href_type;
-
-typedef enum {
- A_HREF = 0,
- A_NAME,
- A_HREF_FILE, /* hdvips file ref */
- A_HREF_URL, /* hdvips URL ref */
- A_HDVIPS_INTERNAL, /* internal ref */
- A_HDVIPS_HREF, /* hdvips href */
- A_HDVIPS_NAME, /* hdvips name */
- A_OTHER,
- A_END,
- A_NONE,
- A_MISMATCH
-} htexAnchorT;
-
-/****************************** helper routines ******************************/
-
-static Boolean
-htex_is_href(htexAnchorT type)
-{
- return type == A_HREF
- || type == A_HREF_FILE
- || type == A_HREF_URL
- || type == A_HDVIPS_HREF
- || type == A_HDVIPS_INTERNAL;
-}
-
-static Boolean
-htex_is_name(htexAnchorT type)
-{
- return type == A_NAME || type == A_HDVIPS_NAME;
-}
-
-static void
-parse_html_special(const char *special, size_t len, const char **beg, const char **end)
-{
- *beg = special;
- while (isspace((int)**beg) || **beg == '=') {
- (*beg)++;
- len--;
- }
- *end = *beg + len - 1;
-
- while (isspace((int)**end) || **end == '>')
- (*end)--;
-
- /* remove quote pairs */
- if (**beg == '"') {
- (*beg)++;
- if (**end == '"') {
- (*end)--;
- }
- }
- /* now end points to last anchor char, move behind that */
- (*end)++;
-}
-
-/*
- Anchor prescanning stuff: We make a pass through all pages in the document
- before displaying them to collect information about mismatched anchors
- (anchors where the opening tag is on some previous page).
- The information is stored in the following struct:
-*/
-struct prescan_info {
- int anchor_depth;
- size_t anchor_num;
- size_t anchor_list_size;
- int *anchor_list;
- /* pointers to either NULL, or to mismatched anchor strings
- (the contents of '<a href="...">' on some previous page),
- for each page */
- size_t pagelist_len;
- char **pagelist;
-};
-
-static struct prescan_info m_prescan_info = { 0, 0, 0, NULL, 0, NULL };
-static struct prescan_info m_save_prescan_info = { 0, 0, 0, NULL, 0, NULL };
-
-
-/*
- Save prescan info from previous page, in case we only have a partial
- scan of the current page and need to start all over.
-*/
-void
-htex_prescan_save(void)
-{
- m_save_prescan_info.anchor_depth = m_prescan_info.anchor_depth;
- m_save_prescan_info.anchor_num = m_prescan_info.anchor_num;
- /* copy over anchor list */
- while (m_save_prescan_info.anchor_depth >= (int)m_save_prescan_info.anchor_list_size) {
- int i;
- m_save_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
- m_save_prescan_info.anchor_list = XREALLOC(m_save_prescan_info.anchor_list,
- m_save_prescan_info.anchor_list_size
- * sizeof *(m_save_prescan_info.anchor_list));
- for (i = 0; i < m_save_prescan_info.anchor_depth; i++) {
- m_save_prescan_info.anchor_list[i] = m_prescan_info.anchor_list[i];
- }
- }
- /* the page list of anchor strings can only have had its current position modified;
- we'll simply delete that position in htex_prescan_restore().
- */
-}
-
-/*
- Restore prescan info from m_save_prescan_info.
-*/
-void
-htex_prescan_restore(int pageno)
-{
- m_prescan_info.anchor_depth = m_save_prescan_info.anchor_depth;
- m_prescan_info.anchor_num = m_save_prescan_info.anchor_num;
- /* copy back anchor list */
- if (m_save_prescan_info.anchor_depth > 0) {
- int i;
- /* old list might have been free()d in htex_prescan_reset_firstpass */
- while (m_save_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
- m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
- m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
- m_prescan_info.anchor_list_size
- * sizeof *(m_prescan_info.anchor_list));
- }
- for (i = 0; i < m_save_prescan_info.anchor_depth; i++) {
- m_prescan_info.anchor_list[i] = m_save_prescan_info.anchor_list[i];
- }
- }
- /* reset anchor string info for this page */
- if ((int)m_prescan_info.pagelist_len > pageno) {
- ASSERT(m_prescan_info.pagelist != NULL, "m_prescan_info.pagelist not properly allocated");
- FREE(m_prescan_info.pagelist[pageno]);
- m_prescan_info.pagelist[pageno] = NULL;
- }
-}
-
-/*
- Reset prescan info for first pass (anchor numbers only) to its initial state,
- freeing up allocated resources for anchor_list.
-
-*/
-void
-htex_prescan_reset_firstpass(void)
-{
- MYTRACE((stderr, "resetting anchor_depth to 0!!!!!!!!!!!!"));
- m_prescan_info.anchor_depth = 0;
- m_prescan_info.anchor_num = 0;
- m_prescan_info.anchor_list_size = 0;
- FREE(m_prescan_info.anchor_list);
- m_prescan_info.anchor_list = NULL;
-}
-
-/*
- Reset the prescan info, freeing up all allocated memory.
- Used when e.g. switching to a different file via Ctrl-F.
-*/
-static void
-htex_prescan_reset(void)
-{
- size_t i;
- m_prescan_info.anchor_depth = 0;
- m_prescan_info.anchor_num = 0;
- m_prescan_info.anchor_list_size = 0;
-
- free(m_prescan_info.anchor_list);
- m_prescan_info.anchor_list = NULL;
-
- for (i = 0; i < m_prescan_info.pagelist_len; i++) {
- free(m_prescan_info.pagelist[i]);
- }
- free(m_prescan_info.pagelist);
- m_prescan_info.pagelist = NULL;
- m_prescan_info.pagelist_len = 0;
-}
-
-/*
- Initialize m_prescan_info for scanning a new page.
-*/
-void
-htex_prescan_initpage(void)
-{
- m_prescan_info.anchor_num = 0;
-}
-
-
-Boolean
-htex_prescan_special(const char *cp, int cp_len, struct htex_prescan_data *data)
-{
- UNUSED(cp_len);
- ASSERT(data != NULL, "data argument to htex_prescan_special() mustn't be NULL");
- if (data->pageno + 1 < (int)m_prescan_info.pagelist_len) { /* already scanned this page */
- MYTRACE((stderr, "already scanned page %d", data->pageno+1));
- return False;
- }
-
- /* resize pagelist */
- while (data->pageno >= (int)m_prescan_info.pagelist_len) {
- size_t old_len = m_prescan_info.pagelist_len;
- size_t i;
- MYTRACE((stderr, "============ resizing pagelist to %d", data->pageno + 1));
- m_prescan_info.pagelist_len = data->pageno + 1;
- m_prescan_info.pagelist = XREALLOC(m_prescan_info.pagelist,
- m_prescan_info.pagelist_len * sizeof *m_prescan_info.pagelist);
- /* initialize with NULL values */
- for (i = old_len; i < m_prescan_info.pagelist_len; i++) {
- MYTRACE((stderr, "============ initializing pagelist %d", i));
- m_prescan_info.pagelist[i] = NULL;
- }
- }
-
- if (data->scan_type == HTEX_ANCHOR_STRING) {
- if ((int)m_prescan_info.anchor_num == data->anchor_num) {
- char *anchor;
- const char *beg, *end;
- const char *cp1 = cp;
- const char *ptr = NULL;
- const char *pptr = NULL;
-
- if (memicmp(cp1, "<a href", strlen("<a href")) == 0) {
- cp1 += strlen("<a href");
- parse_html_special(cp1, strlen(cp1), &beg, &end);
- anchor = xmalloc(end - beg + 1);
- memcpy(anchor, beg, end - beg);
- anchor[end - beg] = '\0';
- /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
- m_prescan_info.pagelist[data->pageno] = anchor;
- }
- else if (memcmp(cp1, "/A", 2) == 0) {
- if ((ptr = strstr(cp1 + 2, "/GoToR")) != NULL /* external file */
- && (ptr = strchr(ptr, '(')) != NULL
- && (pptr = strchr(ptr + 1, '(')) != NULL) {
- anchor = xmalloc(pptr - ptr);
- memcpy(anchor, ptr + 1, pptr - ptr - 1);
- anchor[pptr - ptr - 1] = '\0';
- /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
- m_prescan_info.pagelist[data->pageno] = anchor;
- }
- else if ((ptr = strstr(cp1 + 2, "/URI")) != NULL /* external file */
- && (ptr = strchr(ptr, '(')) != NULL
- && (pptr = strchr(ptr + 1, '(')) != NULL) {
- anchor = xmalloc(pptr - ptr);
- memcpy(anchor, ptr + 1, pptr - ptr - 1);
- anchor[pptr - ptr - 1] = '\0';
- /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
- m_prescan_info.pagelist[data->pageno] = anchor;
- }
- }
- else if (memcmp(cp, "/L", 2) == 0) {
- if ((ptr = strstr(cp1 + 2, "/Dest")) != NULL /* internal link */
- && (ptr = strchr(ptr, '(')) != NULL
- && (pptr = strchr(ptr + 1, '(')) != NULL) {
- anchor = xmalloc(pptr - ptr);
- memcpy(anchor, ptr + 1, pptr - ptr - 1);
- anchor[pptr - ptr - 1] = '\0';
- /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
- m_prescan_info.pagelist[data->pageno] = anchor;
- }
- }
- }
- }
- if (memicmp(cp, "<a ", 3) == 0) {
- while (m_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
- m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
- m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
- m_prescan_info.anchor_list_size
- * sizeof *(m_prescan_info.anchor_list));
- }
- ASSERT(m_prescan_info.anchor_depth >= 0, "List should contain previous anchor info");
- m_prescan_info.anchor_list[m_prescan_info.anchor_depth] = m_prescan_info.anchor_num;
- m_prescan_info.anchor_depth++;
- m_prescan_info.anchor_num++;
- }
- else if (memicmp(cp, "</a", 3) == 0) {
- if (m_prescan_info.anchor_depth < 1) {
- /* this can happen when stuff had been prescanned before */
- return False;
- }
- m_prescan_info.anchor_depth--;
- m_prescan_info.anchor_num++;
- }
- else if (memcmp(cp, "H.S end", strlen("H.S end")) == 0) { /* start of anchor */
- while (m_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
- m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
- m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
- m_prescan_info.anchor_list_size
- * sizeof *(m_prescan_info.anchor_list));
- }
- ASSERT(m_prescan_info.anchor_depth >= 0, "List should contain previous anchor info");
- m_prescan_info.anchor_list[m_prescan_info.anchor_depth] = m_prescan_info.anchor_num;
- m_prescan_info.anchor_depth++;
- m_prescan_info.anchor_num++;
-
- }
- else if (memcmp(cp, "H.R end", strlen("H.R end")) == 0 /* end of rect */
- || memcmp(cp, "H.A end", strlen("H.A end")) == 0 /* end of anchor */
- || memcmp(cp, "H.L end", strlen("H.L end")) == 0 /* end of link */
- ) {
- if (m_prescan_info.anchor_depth < 1) {
- /* this can happen when stuff had been prescanned before */
- return False;
- }
- m_prescan_info.anchor_depth--;
- m_prescan_info.anchor_num++;
- }
- return False;
-}
-
-int
-htex_prescan_get_depth(void)
-{
- return m_prescan_info.anchor_depth;
-}
-
-/* copy over pagelist from old_page to new_page */
-void
-htex_prescan_carry_over(int old_page, int new_page)
-{
- ASSERT(old_page >= 0, "old_page out of range");
- ASSERT(old_page < (int)m_prescan_info.pagelist_len, "old_page out of range");
-
- /* resize if needed */
- if (new_page >= (int)m_prescan_info.pagelist_len) {
- size_t old_len = m_prescan_info.pagelist_len;
- size_t i;
- m_prescan_info.pagelist_len = new_page + 1;
- m_prescan_info.pagelist = XREALLOC(m_prescan_info.pagelist,
- m_prescan_info.pagelist_len * sizeof *m_prescan_info.pagelist);
- /* initialize with NULL values */
- for (i = old_len; i < m_prescan_info.pagelist_len; i++) {
- m_prescan_info.pagelist[i] = NULL;
- }
- }
- free(m_prescan_info.pagelist[new_page]);
- /* don't share pointers here */
- if (m_prescan_info.pagelist[old_page] != NULL) {
- m_prescan_info.pagelist[new_page] = xstrdup(m_prescan_info.pagelist[old_page]);
- }
- else {
- m_prescan_info.pagelist[new_page] = NULL;
- }
-}
-
-size_t
-htex_prescan_get_mismatched_anchor_num(size_t depth)
-{
- ASSERT((int)depth <= m_prescan_info.anchor_depth, "depth too large");
- ASSERT(depth <= m_prescan_info.anchor_list_size, "depth too large for lookup list");
-
- return m_prescan_info.anchor_list[m_prescan_info.anchor_depth - 1];
-}
-
-/******************************* end of prescan stuff ******************************/
-
-struct anchor_marker {
- int page; /* page on which marker is located */
- char *filename; /* file in which the marker is located */
- int y_pos; /* vertical position for marker */
- int x_pos; /* horizontal position for marker */
-} g_anchormarker = { -1, NULL, -1, -1 };
-
-static XtIntervalId m_href_timeout_id = 0;
-
-
-struct history_info {
- char *anchor; /* anchor name */
- char *filename; /* name of file in which this anchor is located */
- int page; /* pagenumber on which anchor is located */
-};
-
-struct anchor_info {
- /* anchor contents as strings */
- char *a_name;
- char *a_href;
- htexObjectT object_type;
- /* bounding box info for this anchor */
- int lrx, lry; /* lower-right corner */
- int ulx, uly; /* upper-left corner */
- /* int refpage; /\* page in DVI file for stack of visited anchors *\/ */
- /* char *filename; /\* name of file in which this anchor is located, for visited anchors *\/ */
- int prev_wrapped; /* index of prev elem, for wrapped hrefs, or -1 */
- int next_wrapped; /* index of next elem, for wrapped hrefs, or -1 */
-};
-
-struct htex_page_info {
- struct anchor_info *anchors; /* anchor info */
- int tot_cnt; /* anchor info size */
- int curr_cnt; /* current number of anchor on page */
- int page; /* page in DVI file this anchor info refers to */
- int have_wrapped; /* -1 if no wrapped anchor on beginning of page, or index of wrapped anchor */
-};
-
-/* file-scope globals ... */
-/* record x and y positions of current anchor, to recognize linebreaks in anchors */
-static int x_pos_bak = 0;
-static int y_pos_bak = 0;
-/* holds all anchors on current page */
-static struct htex_page_info htex_page_info = { NULL, 0, 0, -1, -1 };
-
-/*
- double linked list with history of clicked links, for htex_forward/htex_back
-*/
-static struct dl_list *htex_history = NULL; /* current list insertion point */
-
-struct htex_anchor_stack_elem {
- htexAnchorT type; /* type of anchor (href, anchor, ...) */
- int anchor_num; /* number of this anchor on page (same as curr_cnt in struct htex_page_info) */
-};
-
-/*
- * stack datatype and access functions; used for nested anchors
- */
-struct htex_anchor_stack {
- size_t size;
- size_t depth;
- struct htex_anchor_stack_elem *types;
-};
-
-struct visited_anchor {
- int *list;
- size_t list_size;
-};
-
-struct visited_anchors {
- struct visited_anchor *anchors;
- size_t size;
-};
-
-static struct visited_anchors visited_links = { NULL, 0 };
-
-static struct htex_anchor_stack stack = { 0, 0, NULL };
-
-
-
-/* the following list is from
- http://www.iana.org/assignments/uri-schemes
- re-sorted for likeliness. All protocols except for `file'
- are considered remote.
- (i.e. not accessible via the ordinary Unix file system)
-*/
-static const char *remote_URL_schemes[] = {
- "http:", /* Hypertext Transfer Protocol [RFC2068] */
- "ftp:", /* File Transfer Protocol [RFC1738] */
- "https:", /* Hypertext Transfer Protocol Secure [RFC2818] */
- "mailto:", /* Electronic mail address [RFC2368] */
- "news:", /* USENET news [RFC1738] */
- "nntp:", /* USENET news using NNTP access [RFC1738] */
- "telnet:", /* Reference to interactive sessions [RFC1738] */
- "nfs:", /* network file system protocol [RFC2224] */
- "gopher:", /* The Gopher Protocol [RFC1738] */
- "wais:", /* Wide Area Information Servers [RFC1738] */
- /* the only exception: */
- /* "file:", */ /* Host-specific file names [RFC1738] */
- "prospero:", /* Prospero Directory Service [RFC1738] */
- "z39.50s", /* Z39.50 Session [RFC2056] */
- "z39.50r", /* Z39.50 Retrieval [RFC2056] */
- "cid:", /* content identifier [RFC2392] */
- "mid:", /* message identifier [RFC2392] */
- "vemmi:", /* versatile multimedia interface [RFC2122] */
- "service:", /* service location [RFC2609] */
- "imap:", /* internet message access protocol [RFC2192] */
- "acap:", /* application configuration access protocol [RFC2244] */
- "rtsp:", /* real time streaming protocol [RFC2326] */
- "tip:", /* Transaction Internet Protocol [RFC2371] */
- "pop:", /* Post Office Protocol v3 [RFC2384] */
- "data:", /* data [RFC2397] */
- "dav:", /* dav [RFC2518] */
- "opaquelocktoken:", /* opaquelocktoken [RFC2518] */
- "sip:", /* session initiation protocol [RFC2543] */
- "tel:", /* telephone [RFC2806] */
- "fax:", /* fax [RFC2806] */
- "modem:", /* modem [RFC2806] */
- "ldap:", /* Lightweight Directory Access Protocol [RFC2255] */
- "soap.beep:", /* soap.beep [RFCSOAP] */
- "soap.beeps:", /* soap.beeps [RFCSOAP] */
- /* Reserved URI Scheme Names: */
- "afs:", /* Andrew File System global file names */
- "tn3270:", /* Interactive 3270 emulation sessions */
- "mailserver:", /* Access to data available from mail servers */
- NULL
-};
-
-/* prototypes */
-static void htex_erase_anchormarker(XtPointer client_data, XtIntervalId *id);
-static void htex_draw_anchormarker(int y);
-
-
-static void
-resize_info_if_needed(struct htex_page_info *info)
-{
- /* resize info if needed */
- if (info->curr_cnt + 2 >= info->tot_cnt) {
- int i;
- while (info->curr_cnt + 2 >= info->tot_cnt) {
- info->tot_cnt += HTEX_ALLOC_STEP;
- }
- info->anchors = XREALLOC(info->anchors, info->tot_cnt * sizeof *(info->anchors));
- for (i = info->curr_cnt; i < info->tot_cnt; i++) {
- /* fprintf(stderr, "initializing info at index %d\n", i); */
- info->anchors[i].a_href = NULL;
- info->anchors[i].a_name = NULL;
- /* info->anchors[i].filename = NULL; */
- info->anchors[i].ulx = INT_MAX;
- info->anchors[i].uly = INT_MAX;
- info->anchors[i].lrx = 0;
- info->anchors[i].lry = 0;
- info->anchors[i].object_type = HTEX_TEXT;
- info->anchors[i].prev_wrapped = -1;
- info->anchors[i].next_wrapped = -1;
- }
- }
-}
-
-static void
-init_visited_links(struct visited_anchors *links, int total_pages, Boolean new_dvi_file)
-{
- size_t i, old_size = links->size;
- if (new_dvi_file) {
- /* free old list */
- for (i = 0; i < old_size; i++) {
- FREE(links->anchors[i].list);
- links->anchors[i].list = NULL;
- links->anchors[i].list_size = 0;
- }
- }
- if (links->size <= (size_t)total_pages) {
- MYTRACE((stderr, "resetting visited links (%d != %d)", links->size, total_pages));
- links->size = total_pages + 1;
- links->anchors = XREALLOC(links->anchors, (links->size + 1) * sizeof *(links->anchors));
- for (i = old_size; i < links->size; i++) {
- MYTRACE((stderr, "+++ initializing visited links for page %d", i));
- links->anchors[i].list = NULL;
- links->anchors[i].list_size = 0;
- }
- }
-}
-
-#if 0
-static void
-show_visited(struct visited_anchors *links, int pageno)
-{
- size_t i;
- fprintf(stderr, "visited links on page %d:\n", pageno);
- for (i = 0; i < links->anchors[pageno].list_size; i++) {
- fprintf(stderr, "%d ", links->anchors[pageno].list[i]);
- }
- fprintf(stderr, "\n");
-}
-#endif
-
-static void
-save_in_list(struct visited_anchors *links, int pageno, int idx)
-{
- links->anchors[pageno].list
- = XREALLOC(links->anchors[pageno].list,
- (links->anchors[pageno].list_size + 1)
- * sizeof *(links->anchors[pageno].list));
- links->anchors[pageno].list[links->anchors[pageno].list_size] = idx;
- links->anchors[pageno].list_size++;
-}
-
-static void
-set_visited(struct visited_anchors *links, int pageno, int anchor_num)
-{
- int i;
- /* is it already present? */
- for (i = 0; i < (int)links->anchors[pageno].list_size; i++) {
- if (links->anchors[pageno].list[i] == anchor_num)
- return;
- }
- save_in_list(links, pageno, anchor_num);
- i = anchor_num;
- /* also set previous/next of this anchor to visited */
- while ((i = htex_page_info.anchors[i].prev_wrapped) != -1) {
- TRACE_HTEX((stderr, "set_visited: setting prev_wrapped %d to visited too", i));
- save_in_list(links, pageno, i);
- }
- i = anchor_num;
- while ((i = htex_page_info.anchors[i].next_wrapped) != -1) {
- TRACE_HTEX((stderr, "set_visited: setting next_wrapped %d to visited too", i));
- save_in_list(links, pageno, i);
- }
-#if 0
- show_visited(links, pageno);
-#endif
-}
-
-static Boolean
-is_visited(struct visited_anchors *links, int pageno, int anchor_num)
-{
- size_t i;
-
- ASSERT((size_t)pageno < links->size, "too few elements in links structure");
-
- for (i = 0; i < links->anchors[pageno].list_size; i++) {
- if (links->anchors[pageno].list[i] == anchor_num) {
- return True;
- }
- }
- return False;
-}
-
-static void
-push_stack(struct htex_anchor_stack *stack, htexAnchorT type, int anchor_num)
-{
- size_t i = 0;
- if (stack->depth >= stack->size) {
- stack->size += HTEX_ALLOC_STEP;
- stack->types = XREALLOC(stack->types, stack->size * sizeof *(stack->types));
- for (i = stack->depth; i < stack->size; i++) {
- stack->types[i].type = A_NONE;
- stack->types[i].anchor_num = -1;
- }
- }
- stack->types[stack->depth].type = type;
- stack->types[stack->depth].anchor_num = anchor_num;
- stack->depth++;
-#if 0
- {
- fprintf(stderr, "PUSH - stack is now: \n");
- for (i = 0; i < stack->depth; i++)
- fprintf(stderr, "%d:%d ", i, stack->types[i]);
- MYTRACE(stderr, "\n");
- }
-#endif
-}
-
-static htexAnchorT
-pop_stack(struct htex_anchor_stack *stack, int *anchor_num)
-{
- htexAnchorT ret;
-
- if (stack->depth < 1) {
- return A_MISMATCH;
- }
-
-#if 0
- {
- int i;
- MYTRACE((stderr, "POP - stack is now: "));
- for (i = 0; i < stack->depth; i++)
- MYTRACE((stderr, "%d:%d ", i, stack->types[i]));
- MYTRACE((stderr, ""));
- }
-#endif
- stack->depth--;
- ret = stack->types[stack->depth].type;
- *anchor_num = stack->types[stack->depth].anchor_num;
- stack->types[stack->depth].type = A_NONE;
- stack->types[stack->depth].anchor_num = -1;
- return ret;
-}
-
-
-/* return True if stack contains an A_HREF, False else */
-static Boolean
-get_href_depth(const struct htex_anchor_stack *stack)
-{
- size_t i;
- for (i = 0; i <= stack->depth; i++) {
- ASSERT(stack->types != NULL, "types musn't be NULL!");
- if (htex_is_href(stack->types[i].type))
- return True;
- }
- return False;
-}
-
-static htexAnchorT
-peek_stack(struct htex_anchor_stack *stack, int *anchor_num)
-{
- if (stack->depth < 1) {
- MYTRACE((stderr, "Xdvi warning: wrong nesting of anchors on page %d", current_page));
- *anchor_num = -1;
- return A_NONE;
- }
-
- *anchor_num = stack->types[stack->depth - 1].anchor_num;
- return stack->types[stack->depth - 1].type;
-}
-
-/* routines for coloring the anchors */
-static void
-push_colorspecial(void)
-{
- int i;
-
- i = htex_page_info.curr_cnt - 1;
- /* apply color if needed */
- if (resource.link_style > 1) { /* colored links are wanted */
- Boolean visited = False;
-
- ASSERT(i >= 0, "i mustn't be negative");
- if (is_visited(&visited_links, current_page, i)) {/* || wrapped_anchor_is_visited(i)) { */
- visited = True;
- }
-
- MYTRACE((stderr, "anchor %d, %s is %s\n",
- htex_page_info.curr_cnt - 1, htex_page_info.anchors[htex_page_info.curr_cnt - 1].a_href,
- visited ? "******* visited ****** " : "not visited"));
- if ((visited && resource.visited_link_color != NULL)
- || (! visited && resource.link_color != NULL)) {
- color_special(visited ? g_visited_link_color_rgb : g_link_color_rgb);
- }
- }
-}
-
-static void
-pop_colorspecial(void)
-{
- color_special("pop");
-}
-
-/* return filename if it's a local file, NULL else */
-const char *
-is_local_file(const char *filename)
-{
- int i;
- if (strchr(filename, ':') != NULL) {
- if (memicmp(filename, "file:", strlen("file:")) == 0) {
- TRACE_HTEX((stderr, "%s uses file scheme", filename));
- filename += strlen("file:");
- /*
- skip over `//localhost' part, and skip first `/' iff the
- absolute path starts with `//' (as required by RFC2396,
- but in the past most browsers/applications didn't support
- this).
- */
- if (memicmp(filename, "//localhost", strlen("//localhost")) == 0) {
- filename += strlen("//localhost");
- }
- if (memicmp(filename, "//", 2) == 0) {
- filename += 1;
- }
- return filename;
- }
-
- /* check remote schemes */
- for (i = 0; remote_URL_schemes[i] != NULL; i++) {
- if (memicmp(filename, remote_URL_schemes[i], strlen(remote_URL_schemes[i])) == 0) {
- TRACE_HTEX((stderr, "%s is a remote scheme", filename));
- return NULL;
- }
- }
- }
- /* in all other cases, treat it as an ordinary filename */
- TRACE_HTEX((stderr, "%s is an ordinary filename", filename));
- return filename;
-}
-
-
-static char *
-parse_anchortext(const char *input, int len)
-{
- char *anchor = NULL;
- const char *beg, *end;
-
- parse_html_special(input, len, &beg, &end);
-
- anchor = XMALLOC(anchor, end - beg + 1);
- memcpy(anchor, beg, end - beg);
- anchor[end - beg] = '\0';
- return anchor;
-}
-
-static void
-add_anchor(struct htex_page_info *info, htexAnchorT type,
- const char *str, size_t len,
- int pageno, char *filename)
-{
- UNUSED(pageno);
- UNUSED(filename);
-
- resize_info_if_needed(info);
-
- ASSERT(htex_is_name(type) || htex_is_href(type), "This doesn't look like a valid anchor");
- /* add an anchor or a href, depending on `type' */
- if (type == A_HREF) {
- if (info->anchors[info->curr_cnt].a_href == NULL) {
- info->anchors[info->curr_cnt].a_href = parse_anchortext(str, len);
- }
- TRACE_HTEX((stderr, "adding HREF %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
- }
- else if (type == A_HREF_URL) {
- if (info->anchors[info->curr_cnt].a_href == NULL) {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
- strncpy(info->anchors[info->curr_cnt].a_href, str, len);
- info->anchors[info->curr_cnt].a_href[len] = '\0';
- }
- TRACE_HTEX((stderr, "adding HREF_URL %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
- }
- else if (type == A_HDVIPS_INTERNAL) {
- if (info->anchors[info->curr_cnt].a_href == NULL) {
- /* dynamically add a `#' prefix */
- if (str[0] != '#') {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + 2);
- strcpy(info->anchors[info->curr_cnt].a_href, "#");
- memcpy(info->anchors[info->curr_cnt].a_href + 1, str, len);
- info->anchors[info->curr_cnt].a_href[len + 1] = '\0';
- }
- else {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
- strncpy(info->anchors[info->curr_cnt].a_href, str, len);
- info->anchors[info->curr_cnt].a_href[len] = '\0';
- }
- }
- TRACE_HTEX((stderr, "adding HREF_URL %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
- }
- else if (type == A_HREF_FILE) {
- if (info->anchors[info->curr_cnt].a_href == NULL) {
- /* dynamically add a `file:' extension */
- if (memcmp(str, "file:", strlen("file:")) == 0) {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
- strncpy(info->anchors[info->curr_cnt].a_href, str, len);
- info->anchors[info->curr_cnt].a_href[len] = '\0';
- }
- else {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + strlen("file:") + 1);
- strcpy(info->anchors[info->curr_cnt].a_href, "file:");
- memcpy(info->anchors[info->curr_cnt].a_href + strlen("file:"),
- str, len);
- info->anchors[info->curr_cnt].a_href[len + strlen("file:")] = '\0';
- }
- }
- TRACE_HTEX((stderr, "adding HREF_FILE %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
- }
- else if (type == A_NAME) {
- if (info->anchors[info->curr_cnt].a_name == NULL) {
- info->anchors[info->curr_cnt].a_name = parse_anchortext(str, len);
- }
- TRACE_HTEX((stderr, "adding NAME %d: %s", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
- }
- else if (type == A_HDVIPS_HREF) {
- if (info->anchors[info->curr_cnt].a_href == NULL) {
- info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
- strncpy(info->anchors[info->curr_cnt].a_href, str, len);
- info->anchors[info->curr_cnt].a_href[len] = '\0';
- }
- TRACE_HTEX((stderr, "adding HDVIPS_HREF %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
- }
- else if (type == A_HDVIPS_NAME) {
- if (info->anchors[info->curr_cnt].a_name == NULL) {
- info->anchors[info->curr_cnt].a_name = xmalloc(len + 1);
- strncpy(info->anchors[info->curr_cnt].a_name, str, len);
- info->anchors[info->curr_cnt].a_name[len] = '\0';
- }
- TRACE_HTEX((stderr, "adding HDVIPS_NAME %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
- }
-}
-
-static void
-set_anchor_size(struct htex_page_info *info, int index,
- int ulx, int uly, int lrx, int lry)
-{
- struct anchor_info *anchor;
-
- ASSERT(info->anchors != NULL, "info->anchors should have been allocated before");
- ASSERT(index < info->curr_cnt, "info too small");
-
- anchor = &(info->anchors[index]);
-
- anchor->ulx = ulx;
- anchor->uly = uly;
- anchor->lrx = lrx;
- anchor->lry = lry;
-}
-
-void
-htex_set_objecttype(htexObjectT type)
-{
- htex_page_info.anchors[htex_page_info.curr_cnt - 1].object_type = type;
-}
-
-void
-htex_set_anchorsize(int ulx, int uly, int lrx, int lry)
-{
- set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1,
- ulx, uly, lrx, lry);
-}
-
-static void
-enlarge_anchor_size(struct htex_page_info *info, int index,
- int ulx, int uly, int lrx, int lry)
-{
- struct anchor_info *anchor;
-
- ASSERT(info->anchors != NULL, "info->anchors should have been allocated before");
- ASSERT(index < info->curr_cnt, "info too small");
-
- /* fprintf(stderr, "enlarging anchor at index %d; %s\n", index, info->anchors[index].a_href); */
- anchor = &(info->anchors[index]);
-
- if (ulx < anchor->ulx) {
- anchor->ulx = ulx;
- }
- if (uly < anchor->uly) {
- anchor->uly = uly;
- }
- if (lrx > anchor->lrx) {
- anchor->lrx = lrx;
- }
- /* set lry only for first character, since this will be used
- to position underline */
- /* if (lry > anchor->lry && anchor->lry == 0) { */
- if (lry > anchor->lry) {
- anchor->lry = lry;
- }
-}
-
-static void
-reset_page_info(struct htex_page_info *info, int pageno, Boolean force_init)
-{
- int i, dummy;
-
- if (force_init || pageno != info->page) {
-#if 0
- fprintf(stderr, "%d or %d != %d: resetting anchorinfo for page %d (%d anchors)\n",
- force_init, pageno, info->page, current_page, info->curr_cnt);
-#endif
- ASSERT(info->curr_cnt == 0 || info->anchors != NULL, "inconsistency in info structure");
- /* re-initialize all values */
- for (i = 0; i < info->curr_cnt; i++) {
- TRACE_HTEX((stderr, "----- resetting info for anchor %d", i));
- FREE(info->anchors[i].a_name);
- FREE(info->anchors[i].a_href);
- info->anchors[i].a_name = NULL;
- info->anchors[i].a_href = NULL;
- info->anchors[i].ulx = INT_MAX;
- info->anchors[i].uly = INT_MAX;
- info->anchors[i].lrx = 0;
- info->anchors[i].lry = 0;
- info->anchors[i].object_type = HTEX_TEXT;
- info->anchors[i].prev_wrapped = -1;
- info->anchors[i].next_wrapped = -1;
- }
- }
- if (pageno != info->page) { /* reset info */
- free(info->anchors);
- info->anchors = NULL;
- info->tot_cnt = 0;
- }
- TRACE_HTEX((stderr, "---------------- setting curr_cnt to 0, and emptying stack"));
- info->page = pageno;
- info->curr_cnt = 0;
- info->have_wrapped = -1;
- while (stack.depth > 0)
- pop_stack(&stack, &dummy);
-}
-
-/*
- * htex_initpage does what's neccessary at the beginning of a page:
- * - re-initialize geometry info if file or page size has changed (according to size_changed),
- * - re-initialize visited links info if file has changed (according to new_dvi_file),
- * - take care of mismatched anchors at the beginning of the page.
- */
-void
-htex_initpage(Boolean new_dvi_file, Boolean size_changed, int pageno)
-{
- reset_page_info(&htex_page_info, pageno, size_changed | new_dvi_file);
- init_visited_links(&visited_links, total_pages, new_dvi_file);
-
-#if 0
- show_visited(&visited_links, pageno);
-#endif
-
- if (pageno > 0
- && (int)m_prescan_info.pagelist_len > pageno /* pagelist_len will be 0 for file with no hyperlinks */
- && m_prescan_info.pagelist[pageno - 1] != NULL) {
- add_anchor(&htex_page_info, A_HREF,
- m_prescan_info.pagelist[pageno - 1],
- strlen(m_prescan_info.pagelist[pageno - 1]),
- pageno, NULL);
- htex_page_info.curr_cnt++;
- MYTRACE((stderr, "++++++++++ mismatched anchor text (at %d): |%s|",
- htex_page_info.curr_cnt - 1, m_prescan_info.pagelist[pageno - 1]));
- /* x_pos_bak = y_pos_bak = INT_MAX; */
- x_pos_bak = y_pos_bak = INT_MAX;
- set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, 0, 0, 1, 1);
- htex_page_info.have_wrapped = htex_page_info.curr_cnt - 1;
- if (bg_current != NULL) { /* only if it has been initialized by redraw_page in events.c */
- push_colorspecial();
- }
- /* else { */
- /* fprintf(stderr, "----------------------- NOT pushing color, waiting ...\n"); */
- /* } */
- push_stack(&stack, A_HREF, htex_page_info.curr_cnt - 1);
- }
-}
-
-/* Returns a PostScript literal text string inside parentheses. The
- scanner works according to "PostScript language reference, third
- edition" - Sec. 3.2.2. The specification is implemented completely:
- balanced parentheses and all escape sequences are considered.
-
- The argument STR is expected to be a pointer to the first character
- after the opening parenthesis. The function returns NULL if the
- text string is malformed. Otherwise the return value points to
- an allocated string which should be freed by the calling function.
-*/
-static char *
-scan_ps_literal_text_string(const char *str)
-{
- const char *s;
- char *cp, *c;
- int count = 1;
-
- /* Search end of string by considering balanced parentheses. */
- for (s = str; *s; s++)
- if (*s == '\\' && *(s+1))
- s++;
- else if (*s == '(')
- count++;
- else if (*s == ')')
- if (! --count)
- break;
-
- if (!*s)
- return NULL;
-
-
- if ((cp = malloc((s - str + 1) * sizeof(*cp))) == NULL) {
- XDVI_ERROR((stderr, "Not enough memory"));
- return NULL;
- }
-
- /* copy string while translating escape sequences */
- for (c = cp; str < s; str++) {
- if (*str == '\\') {
- switch (*++str) {
- case 'n': *c++ = '\n'; break;
- case 'r': *c++ = '\r'; break;
- case 't': *c++ = '\t'; break;
- case 'b': *c++ = '\b'; break;
- case 'f': *c++ = '\f'; break;
- case '\n': break;
- case '\r': if (*(str + 1) == '\n') str++; break;
- default:
- if (isdigit((unsigned char)*str)) {
- char number[] = "xxx";
- char *end;
- strncpy(number, str, 3);
- *c++ = strtoul(number, &end, 8);
- str += end - number - 1;
- }
- else {
- *c++ = *str; /* ignore \ if followed by another char,
- including ( and ) and \ */
- }
- }
- }
- else {
- *c++ = *str;
- }
- }
- *c = '\0';
-
- return cp;
-}
-
-static void
-hdvips_add_anchor(struct htex_page_info *info, htexAnchorT type, const char *str)
-{
- char *ptr;
- if ((ptr = scan_ps_literal_text_string(str)) != NULL) {
- int curr_cnt_bak = info->curr_cnt;
- /* overwrite previously created dummy/wrapped anchors */
- ASSERT(info->curr_cnt > 0, "hdvips_add_anchor must be called after add_anchor()!");
-
- while (info->curr_cnt > 0
- && info->anchors[info->curr_cnt - 1].a_href != NULL
- && (strcmp(info->anchors[info->curr_cnt - 1].a_href, "__WRAPPED__") == 0
- || strcmp(info->anchors[info->curr_cnt - 1].a_href, "__DUMMY__") == 0)) {
- info->curr_cnt--;
- free(info->anchors[info->curr_cnt].a_href);
- free(info->anchors[info->curr_cnt].a_name);
- info->anchors[info->curr_cnt].a_href = info->anchors[info->curr_cnt].a_name = NULL;
- add_anchor(info, type, ptr, strlen(ptr), 0, NULL);
- }
- info->curr_cnt = curr_cnt_bak;
- free(ptr);
- }
- else {
- MYTRACE((stderr, "Xdvi warning: skipping malformed hdvips link `%s'", str));
- }
-}
-
-/*
- * htex_reset_page: invoked when drawing was interrupted,
- * assumes that htex_page_info is in an inconsistent state and resets it.
- */
-void
-htex_reset_page(int pageno)
-{
- reset_page_info(&htex_page_info, pageno, True);
-}
-
-/* returns True iff inside a href tag */
-Boolean
-htex_scan_anchor(const char *cp, size_t len)
-{
- char *ptr;
-
- if (memicmp(cp, "</a>", 4) == 0) { /* end tag */
- /* struct anchor_info *anchor; */
- int num;
- htexAnchorT type = pop_stack(&stack, &num);
- if (type == A_MISMATCH)
- return False;
-
- /* ASSERT(htex_page_info.curr_cnt - 1 >= 0, "Index out of range"); */
- /* anchor = &(htex_page_info.anchors[htex_page_info.curr_cnt - 1]); */
-
- /* reset color if needed */
- if (resource.link_style > 1 && resource.link_color != NULL && htex_is_href(type))
- pop_colorspecial();
- }
- else if (memicmp(cp, "<a ", 3) == 0) {
- m_href_type = HYPERTEX_LINK;
- cp += 3; /* skip over `<a ' part */
- len -= 3;
- TRACE_HTEX((stderr, "scan_anchor: |%s|", cp));
- if (memicmp(cp, "name", 4) == 0) {
- add_anchor(&htex_page_info, A_NAME, cp + 4, len - 4, 0, NULL);
- htex_page_info.curr_cnt++;
- push_stack(&stack, A_NAME, htex_page_info.curr_cnt);
- }
- else if (memicmp(cp, "href", 4) == 0) {
- add_anchor(&htex_page_info, A_HREF, cp + 4, len - 4, 0, NULL);
- htex_page_info.curr_cnt++;
- push_stack(&stack, A_HREF, htex_page_info.curr_cnt);
-
- /* MYTRACE((stderr, "NON-WRAPPED ANCHOR at %d,%d!", PXL_H, PXL_V)); */
- push_colorspecial();
- x_pos_bak = PXL_H;
- y_pos_bak = PXL_V;
- /* set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, PXL_H, PXL_V, PXL_H + 10, PXL_V + 10); */
- }
- else {
- XDVI_WARNING((stderr, "Skipping unimplemented htex special `%s'", cp));
- push_stack(&stack, A_OTHER, htex_page_info.curr_cnt);
- }
- }
- else if (memcmp(cp, "H.S end", strlen("H.S end")) == 0) {
- /* start of anchor, link or rect. We just assume that the link
- target will have length 0, so when we see text between H.S
- and H.R, assume that it's the link text.
- */
- m_href_type = HDVIPS_LINK;
- /* add dummy */
- add_anchor(&htex_page_info, A_HDVIPS_HREF, "__DUMMY__", strlen("__DUMMY__"), 0, NULL);
- htex_page_info.curr_cnt++;
- push_stack(&stack, A_HREF, htex_page_info.curr_cnt - 1);
- push_colorspecial();
- x_pos_bak = PXL_H;
- y_pos_bak = PXL_V;
- return True;
- }
- else if (memcmp(cp, "H.R end", strlen("H.R end")) == 0 /* end of rect */
- || memcmp(cp, "H.A end", strlen("H.A end")) == 0 /* end of anchor */
- || memcmp(cp, "H.L end", strlen("H.L end")) == 0 /* end of link */
- ) {
- int num;
- htexAnchorT type = pop_stack(&stack, &num);
- if (type == A_MISMATCH)
- return False;
- if (resource.link_style > 1 && resource.link_color != NULL)
- pop_colorspecial();
- return False;
- }
- /* add anchor texts for hdvips links */
- else if (memcmp(cp, "/A", 2) == 0) { /* possibly an hdvips external link */
- /* fprintf(stderr, "+++++ EXT: |%s|\n", cp); */
- if ((ptr = strstr(cp + 2, "/GoToR")) != NULL /* external file */
- && (ptr = strchr(ptr, '(')) != NULL) {
- hdvips_add_anchor(&htex_page_info, A_HREF_FILE, ptr + 1);
- }
- else if ((ptr = strstr(cp + 2, "/URI")) != NULL /* URL */
- && (ptr = strchr(ptr, '(')) != NULL) {
- hdvips_add_anchor(&htex_page_info, A_HREF_URL, ptr + 1);
- }
- return False;
- }
- else if (memcmp(cp, "/L", 2) == 0) { /* possibly an hdvips internal link */
- if ((ptr = strstr(cp + 2, "/Dest")) != NULL
- && (ptr = strchr(ptr, '(')) != NULL) {
- hdvips_add_anchor(&htex_page_info, A_HDVIPS_INTERNAL, ptr + 1);
- }
- return False;
- }
- else if (memcmp(cp, "/V", 2) == 0) { /* possibly an hdvips anchor */
- if ((ptr = strstr(cp + 2, "/Dest")) != NULL
- && (ptr = strchr(ptr, '(')) != NULL) {
- hdvips_add_anchor(&htex_page_info, A_HDVIPS_NAME, ptr + 1);
- }
- return False;
- }
- else { /* unrecognized tag */
- if (globals.warn_spec_now) {
- XDVI_WARNING((stderr, "Ignoring unknown hyperref special `%s'", cp));
- }
- return False;
- }
- return get_href_depth(&stack);
-}
-
-void
-htex_record_position(int ulx, int uly, int w, int h)
-{
- int lrx, lry;
- int y_delta;
-
- if (!INSIDE_MANE_WIN) /* this would give wrong values */
- return;
-
- lrx = ulx + w;
- lry = uly + h;
-
- y_delta = lry - uly;
-
- /* heuristics for creating new bounding box at what might be linebreaks */
- if (lrx < x_pos_bak /* ordinary linebreak */
- || lry + y_delta < y_pos_bak) { /* column break (from bottom of 1st to top 2nd column) */
- htexAnchorT type;
- int idx, prev, curr;
- /* get anchor index of topmost stack item, to find the matching open tag */
- if ((type = peek_stack(&stack, &idx)) == A_NONE) {
- /* fprintf(stderr, "!!!!!!!!!!!! couldn't find opening tag for this wrapped link!"); */
- return;
- }
- ASSERT(idx >= 0, "Index out of range");
- /* fprintf(stderr, "wrapped link: index %d, type %d\n", idx, type); */
- /* get correct idx */
- if (m_href_type == HYPERTEX_LINK) {
- while (htex_page_info.anchors[idx].a_href == NULL && idx > 0) {
- idx--;
- }
- if (htex_page_info.anchors[idx].a_href == NULL && idx == 0) {
- XDVI_ERROR((stderr, "Couldn't find wrapped anchor for idx %d, page %d!", idx, current_page));
- return;
- }
- add_anchor(&htex_page_info, A_HREF,
- htex_page_info.anchors[idx].a_href,
- strlen(htex_page_info.anchors[idx].a_href),
- 0, NULL);
- }
- else {
- add_anchor(&htex_page_info, A_HREF, "__WRAPPED__", strlen("__WRAPPED__"), 0, NULL);
- }
- htex_page_info.curr_cnt++;
- /* add wrapping info */
- if (htex_page_info.have_wrapped >= 0) {
- /* this is the only case where some other material might have come between
- this and the previous anchor */
- prev = htex_page_info.have_wrapped;
- htex_page_info.have_wrapped = -1;
- }
- else {
- prev = htex_page_info.curr_cnt - 2;
- }
- curr = htex_page_info.curr_cnt - 1;
- ASSERT(prev >= 0, "Index out of range");
-
- /* fprintf(stderr, "setting prev to %d, curr to %d\n", prev, curr); */
- htex_page_info.anchors[prev].next_wrapped = curr;
- htex_page_info.anchors[curr].prev_wrapped = prev;
- /* initialize it to cover current character */
- set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, ulx, uly, lrx, lry);
- }
- else {
- int prev_idx = htex_page_info.curr_cnt - 1;
-
- if (prev_idx >= 0) {
- enlarge_anchor_size(&htex_page_info, prev_idx, ulx, uly, lrx, lry);
- }
- else {
- MYTRACE((stderr, "!!!!!!!!!!!! Bug? prev_idx < 0"));
- }
- }
- x_pos_bak = lrx;
- y_pos_bak = uly;
-}
-
-#if 0
-static void
-show_history(void)
-{
- struct dl_list *ptr = htex_history;
- struct history_info *info = ptr->item;
- int i;
-
- fprintf(stderr, "**************** history: %s, %d, %s\n", info->filename, info->page, info->anchor);
- for (; ptr->prev != NULL; ptr = ptr->prev) { ; }
- for (i = 0; ptr != NULL; ptr = ptr->next, i++) {
- info = ptr->item;
- fprintf(stderr, "elem %d: %s, %d, %s\n", i, info->filename, info->page, info->anchor);
- MYTRACE((stderr, "elem: %p, prev: %p, next: %p", (void *)ptr, (void *)ptr->prev, (void *)ptr->next));
- }
-}
-#endif
-
-/* check for names like foo/bar.dvi#link, return copy of
- link truncated at the `#' if found (NULL else), and
- save `link' into resource.anchor_pos for later use.
-*/
-static char *
-check_relative_name(const char *link)
-{
- char *ptr;
- TRACE_HTEX((stderr, "check_relative_name: |%s|", link));
- if ((ptr = strchr(link, '#')) != NULL
- && ptr > link + 4
- && (memicmp(ptr - 4, ".dvi", 4) == 0)) {
- char *new_link = xstrdup(link);
- new_link[ptr - link] = '\0'; /* truncate the copy */
- free(g_anchor_pos);
- g_anchor_pos = xstrdup(ptr + 1);
- g_anchor_len = strlen(g_anchor_pos);
-
- return new_link;
- }
- else { /* reset g_anchor_pos */
- free(g_anchor_pos);
- g_anchor_pos = NULL;
- }
- return NULL;
-}
-
-static void
-htex_update_toolbar_navigation(void)
-{
-#if 0
- show_history();
-#endif
-#if defined(MOTIF) && HAVE_XPM
- tb_set_htex_back_sensitivity(htex_history->prev != NULL);
- tb_set_htex_forward_sensitivity(htex_history->next != NULL);
-#endif
-}
-
-void
-htex_back(void)
-{
- struct history_info *info;
-
- if (htex_history == NULL) {
- xdvi_bell();
- statusline_info(STATUS_SHORT, "Hyperref history is empty");
- return;
- }
- info = htex_history->item;
-
- if (htex_history->prev == NULL) {
- xdvi_bell();
-/* statusline_info(STATUS_SHORT, "At begin of history"); */
- htex_update_toolbar_navigation();
- return;
- }
-
- if (strcmp(info->filename, globals.dvi_name) != 0) { /* new filename different */
- Boolean tried_dvi_ext = False;
- char *new_dvi_name = NULL;
-
- if ((new_dvi_name = open_dvi_file_wrapper(info->filename, False, False,
- &tried_dvi_ext, False))
- == NULL) {
-
- statusline_error(STATUS_MEDIUM, "Re-opening file \"%s\" failed!\n", info->filename);
- return;
- }
- else {
- set_dvi_name(new_dvi_name);
- globals.ev.flags |= EV_NEWDOC;
- globals.ev.flags |= EV_PAGEHIST_INSERT;
- /* statusline_info(STATUS_MEDIUM, "Back to file: \"%s\"", globals.dvi_name); */
- }
- }
- else {
- page_history_insert(info->page);
- }
- goto_page(info->page, resource.keep_flag ? NULL : home, False);
-
- MYTRACE((stderr, "curr page now: %d", current_page));
- htex_history = htex_history->prev;
-
- info = htex_history->item;
-
-#if 0
- MYTRACE((stderr, "------ before skipping: %d, %s", info->page, info->anchor));
- show_history();
- while (info->page == current_page && htex_history->prev != NULL) {
- /* skip identical locations */
- MYTRACE((stderr, "+++++++ skipping identical page %d, %s", current_page, info->anchor));
- htex_history = htex_history->prev;
- info = htex_history->item;
- }
- MYTRACE((stderr, "------ after skipping: %d, %s", info->page, info->anchor));
-#endif
-
- htex_update_toolbar_navigation();
-}
-
-
-void
-htex_forward(void)
-{
- struct history_info *info;
- char *link;
-
- if (htex_history == NULL) {
- xdvi_bell();
- statusline_info(STATUS_SHORT, "Hyperref history is empty");
- return;
- }
- if (htex_history->next == NULL) {
- xdvi_bell();
-/* statusline_info(STATUS_SHORT, "At end of history"); */
- return;
- }
-
- htex_history = htex_history->next;
- info = htex_history->item;
- link = info->anchor;
- /* go there */
- if (*link == '#') { /* it's a relative link */
- MYTRACE((stderr, "XXXXXXXX %s:%d: setting anchor to |%s|+1", __FILE__, __LINE__, info->anchor));
- free(g_anchor_pos);
- g_anchor_pos = xstrdup(info->anchor + 1);
- g_anchor_len = strlen(g_anchor_pos);
- globals.ev.flags |= EV_ANCHOR;
- }
- else { /* it's an absolute link */
- char *new_linkname = NULL;
- char *new_dvi_name = NULL;
- Boolean tried_dvi_ext = False;
-
- if ((new_linkname = check_relative_name(link)) != NULL)
- link = new_linkname;
-
- if ((new_dvi_name = open_dvi_file_wrapper(link, False, False,
- &tried_dvi_ext, False)) == NULL) {
- statusline_error(STATUS_MEDIUM, "Re-opening file \"%s\" failed!\n", info->filename);
- free(new_linkname);
- return;
- }
- else {
- set_dvi_name(new_dvi_name);
-
- globals.ev.flags |= EV_NEWDOC;
- goto_page(0, resource.keep_flag ? NULL : home, False);
- globals.ev.flags |= EV_PAGEHIST_INSERT;
-
- if (g_anchor_pos != NULL)
- globals.ev.flags |= EV_ANCHOR;
-
- /* statusline_info(STATUS_MEDIUM, "Loaded file: \"%s\"", globals.dvi_name); */
- free(new_linkname);
- }
- }
-
- htex_update_toolbar_navigation();
-}
-
-/* save this anchor in jump_history, current location in goback_history,
- and update Motif toolbar icons
-*/
-static void
-history_save_anchor(const char *anchor, int current_page, const char *dvi_name)
-{
- struct history_info *item;
-
- if (htex_history == NULL) {
- /* Insert dummy start elem. We need this to prevent dropping
- off from the begin of the list, since otherwise a 1-elem
- list couldn't encode the information whether we can still go
- back. This way it will point to the dummy elem when there's
- no way to go back. */
- struct history_info *start_marker = XMALLOC(start_marker, sizeof *start_marker);
- start_marker->anchor = NULL;
- start_marker->filename = NULL;
- start_marker->page = -1;
- htex_history = dl_list_insert(htex_history, start_marker);
- }
- item = XMALLOC(item, sizeof *item);
- item->anchor = xstrdup(anchor);
- item->filename = xstrdup(dvi_name);
- item->page = current_page;
- htex_history = dl_list_truncate(dl_list_insert(htex_history, item));
-
-#if 0
- MYTRACE((stderr, "==================== after inserting "));
- show_history();
-#endif
-
- htex_update_toolbar_navigation();
-
-}
-
-/*
- * Return anchor string at coordinates x, y, and anchor count in 3rd argument,
- * or NULL if there's no anchor at these coordinates.
- */
-static char *
-get_anchor_at_index(int x, int y, int *count)
-{
- int i;
-
- for (i = 0; i < htex_page_info.curr_cnt; i++) {
- struct anchor_info anchor = htex_page_info.anchors[i];
- /* fprintf(stderr, "getting anchor at index %d; %s\n", i, anchor.a_href); */
- if (anchor.a_href == NULL) {
- continue;
- }
- if (anchor.lry + 2 > y && anchor.uly - 1 < y /* allow some vertical fuzz */
- && anchor.lrx > x && anchor.ulx < x) {
- *count = i;
- return anchor.a_href;
- }
- }
- *count = -1;
- return NULL;
-}
-
-
-/*
- generate exposure events for anchor at index idx, and all anchors wrapping to/from it,
- so that they will be redrawn in `visited' color
-*/
-static void
-redraw_anchors(int idx)
-{
- struct anchor_info anchor = htex_page_info.anchors[idx];
- int other;
- int i = idx;
-#define DO_EXPOSE(lx,ly,rx,ry) (clearexpose(&mane, lx - 20, ly - 3, rx - lx + 26, ry - ly + 6))
-
- /* HACK ALERT: This is a workaround for a coloring problem with wrapped anchors
- (see regression/href/002/url-wrap-test2.dvi):
- We can't change the color on-the-fly for a wrapped anchor, since the special
- is pushed only at the opening tag. So for wrapped anchors, the visited colour
- wouldn't be set correctly. Redrawing the entire page ensures this (but it's ugly).
- Currently this hack overrides the algorithm below for all anchors that have a
- `prev_wrapped' pointer.
- */
- if (htex_page_info.anchors[i].prev_wrapped != -1) {
- globals.ev.flags |= EV_NEWPAGE;
- XSync(DISP, False);
- return;
- }
-
- DO_EXPOSE(anchor.ulx, anchor.uly, anchor.lrx, anchor.lry);
-
- /* previous parts of wrapped anchors: */
- for (i = idx;
- i >= 0 && (other = htex_page_info.anchors[i].prev_wrapped) != -1;
- i--) {
- DO_EXPOSE(htex_page_info.anchors[other].ulx, htex_page_info.anchors[other].uly,
- htex_page_info.anchors[other].lrx, htex_page_info.anchors[other].lry);
- }
-
- /* later parts of wrapped anchors: */
- for (i = idx;
- i < htex_page_info.curr_cnt && (other = htex_page_info.anchors[i].next_wrapped) != -1;
- i++) {
- DO_EXPOSE(htex_page_info.anchors[other].ulx, htex_page_info.anchors[other].uly,
- htex_page_info.anchors[other].lrx, htex_page_info.anchors[other].lry);
- }
-#undef DO_EXPOSE
-}
-
-
-/*
- * Invoked when clicking on a link.
- * newwindow == True means open new window,
- * newwindow == False means jump to link in current window.
- * With newwindow == True, don't update the toolbar navigation icons, since there's nothing to go back.
- */
-Boolean
-htex_handleref(int x, int y, Boolean newwindow)
-{
- char *link;
- int link_num;
-
- /* fprintf(stderr, "---------- htex_handleref!\n"); */
- if (!(globals.cursor.flags & CURSOR_LINK))
- /* When no link cursor is shown, clicking shouldn't jump to link */
- return False;
-
- if ((link = get_anchor_at_index(x, y, &link_num)) != NULL) {
- set_visited(&visited_links, current_page, link_num);
-
- if (*link == '#') { /* it's a relative link */
- if (newwindow) {
- launch_xdvi(globals.dvi_name, link + 1);
- redraw_anchors(link_num);
- return True;
- }
- else {
- history_save_anchor(link, current_page, globals.dvi_name);
- free(g_anchor_pos);
- g_anchor_pos = xstrdup(link + 1);
- g_anchor_len = strlen(g_anchor_pos);
- globals.ev.flags |= EV_ANCHOR;
- redraw_anchors(link_num);
- return True;
- }
- }
- else { /* it's an absolute link */
- char *new_dvi_name = NULL;
- int pageno_bak = current_page;
- char *new_linkname = NULL;
- char *orig_link = link;
- Boolean tried_dvi_ext = False;
-
- MYTRACE((stderr, "OLD FILE: |%s|", globals.dvi_name));
-
- if ((new_linkname = check_relative_name(link)) != NULL)
- link = new_linkname;
-
- if ((new_dvi_name = open_dvi_file_wrapper(link, False, newwindow,
- &tried_dvi_ext, False)) != NULL) {
- /* only save link in history if opening succeeds */
- history_save_anchor(orig_link, pageno_bak, globals.dvi_name);
- set_dvi_name(new_dvi_name);
- if (!newwindow) {
- globals.ev.flags |= EV_NEWDOC;
- goto_page(0, resource.keep_flag ? NULL : home, False);
- globals.ev.flags |= EV_PAGEHIST_INSERT;
-
- MYTRACE((stderr, "NEW FILE: |%s|", globals.dvi_name));
- if (g_anchor_pos != NULL)
- globals.ev.flags |= EV_ANCHOR;
- /* statusline_info(STATUS_MEDIUM, "Loaded file: \"%s\"", dvi_name); */
- }
- else {
- redraw_anchors(link_num);
- }
- }
- free(new_linkname);
- redraw_anchors(link_num);
- return True;
- }
- }
- return False;
-}
-
-/* change cursor and display anchor text in statusline */
-void
-htex_displayanchor(int x, int y)
-{
- static int id_bak = -1;
- static int pageno_bak = -1;
- int id_curr;
- char *anchor_text;
-
- anchor_text = get_anchor_at_index(x, y, &id_curr);
-
- if (anchor_text != NULL) { /* found an anchor */
- if (!(globals.cursor.flags & CURSOR_LINK) && !(globals.cursor.flags & CURSOR_TEXT)) {
- globals.cursor.flags |= CURSOR_LINK;
- globals.ev.flags |= EV_CURSOR;
- }
- /* to prevent flicker, print only when it differs from previous one,
- i.e. when it either has a different ID or is on a different page: */
- if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0
- && (id_curr != id_bak || current_page != pageno_bak)) {
- statusline_info(STATUS_FOREVER, "%s", anchor_text);
- id_bak = id_curr;
- pageno_bak = current_page;
- }
- }
- else { /* not over anchor text, reset cursor and statusline */
- if (globals.cursor.flags & CURSOR_LINK) {
- globals.cursor.flags &= ~CURSOR_LINK;
- globals.ev.flags |= EV_CURSOR;
- }
-
- if (id_bak != -1 && (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
- statusline_clear();
- id_bak = -1;
- }
- }
-}
-
-/*
- * Invoked from all commands that change the shrink factor;
- * forces re-computation of the anchor markers.
- */
-void
-htex_resize_page(void)
-{
- htex_initpage(False, True, current_page);
-}
-
-/*
- * Invoked from all commands that reread the DVI file;
- * resets all link infos.
- * Note: visited_links and anchor stack data
- * are preserved across multiple files, so we don't need to free() them.
- */
-void
-htex_reinit(void)
-{
- htex_prescan_reset();
- htex_initpage(True, True, current_page);
-}
-
-/*
- Underline/highlight anchors if the appropriate resource is set.
- Since this is done after the entire page is parsed, we can't use
- the checks for fg_current and do_color_change(), but need to
- use a separate GC instead.
-*/
-void
-htex_draw_anchormarkers(void)
-{
- int i;
- int rule_height = (globals.page.h / 1000.0);
- XRectangle rect = { -1, -1, 0, 0 };
-
- if (rule_height == 0)
- rule_height = 1;
-
- if (current_page == g_anchormarker.page
- && strcmp(globals.dvi_name, g_anchormarker.filename) == 0
- && g_anchormarker.y_pos > 0) {
- htex_draw_anchormarker(g_anchormarker.y_pos);
- }
-
- if (resource.link_style == 0 || resource.link_style == 2)
- return;
-
- for (i = 0; i < htex_page_info.curr_cnt; i++) {
- struct anchor_info anchor = htex_page_info.anchors[i];
-
- if (anchor.a_href != NULL) {
- int offset;
- Boolean visited = False;
-
-#if 0
- XDrawRectangle(DISP, mane.win, globals.gc.high,
- anchor.ulx, anchor.uly,
- anchor.lrx - anchor.ulx, anchor.lry - anchor.uly);
-
-#endif
-
- if (is_visited(&visited_links, current_page, i)) {/* || wrapped_anchor_is_visited(i)) { */
- visited = True;
- }
- offset = ANCHOR_XTRA_V_BBOX / (double)currwin.shrinkfactor + 0.5;
-
- TRACE_HTEX((stderr, "UNDERLINE: %d, %s is %s", i, anchor.a_href,
- visited ? "******* visited ****** " : "not visited"));
- anchor.ulx -= currwin.base_x;
- anchor.lrx -= currwin.base_x;
- anchor.lry -= currwin.base_y;
- anchor.uly -= currwin.base_y;
-
- /* BUG ALERT: Don't use put_rule here, since this will cause a segfault
- * with the new color code when switching density (#616920)!
- */
- MYTRACE((stderr, "UNDERLINE: checking if %d is visited: %d!", i, visited));
-
- /* if (clip_region_to_rect(&rect)) { */
- if (anchor.object_type == HTEX_IMG) {
- rect.x = anchor.ulx - 1;
- rect.y = anchor.uly - 1;
- rect.width = anchor.lrx - anchor.ulx + 2;
- rect.height = anchor.lry - anchor.uly + 2;
- if (clip_region_to_rect(&rect)) {
- XDrawRectangle(DISP, mane.win,
- visited ? globals.gc.visited_linkcolor : globals.gc.linkcolor,
- rect.x, rect.y,
- rect.width, rect.height);
- }
- }
- else {
- rect.x = anchor.ulx - 1;
- rect.y = anchor.lry + offset;
- rect.width = anchor.lrx - anchor.ulx + 2;
- rect.height = rule_height;
- if (clip_region_to_rect(&rect)) {
- XFillRectangle(DISP, mane.win,
- visited ? globals.gc.visited_linkcolor : globals.gc.linkcolor,
- rect.x, rect.y,
- rect.width, rect.height);
- }
- }
- }
- }
-}
-
-void
-launch_xdvi(const char *filename, const char *anchor_name)
-{
-#define ARG_LEN 32
- int i = 0;
- const char *argv[ARG_LEN];
- char *shrink_arg = NULL;
-
- ASSERT(filename != NULL, "filename argument to launch_xdvi() mustn't be NULL");
-
- argv[i++] = kpse_invocation_name;
- /* FIXME: there's something broken with this and invoking xdvi.bin.
- To reproduce the problem, invoke from the shell:
- xdvi.bin -geometry 829x1172 /usr/share/texmf/doc/programs/kpathsea.dvi
- this will run at 300dpi, i.e. ignore an .Xdefaults setting as opposed to:
- xdvi.bin /usr/share/texmf/doc/programs/kpathsea.dvi
-
- Also, how about the other command-line switches that might have
- been passed to the parent instance? How about things that have been changed
- at run-time, like shrink factor - should they be converted to command-line
- options?
- */
-
- argv[i++] = "-name";
- argv[i++] = "xdvi";
-
- /* start the new instance with the same debug flags as the current instance */
- if (globals.debug != 0) {
- argv[i++] = "-debug";
- argv[i++] = resource.debug_arg;
- }
-
- if (anchor_name != NULL) {
- argv[i++] = "-anchorposition";
- argv[i++] = anchor_name;
- }
-
- argv[i++] = "-s";
- shrink_arg = XMALLOC(shrink_arg, LENGTH_OF_INT + 1);
- sprintf(shrink_arg, "%d", currwin.shrinkfactor);
- argv[i++] = shrink_arg;
-
- argv[i++] = filename; /* FIXME */
-
- argv[i++] = NULL;
- ASSERT(i <= ARG_LEN, "Too few elements in argv[]");
-
- if (globals.debug & DBG_HTEX) {
- fprintf(stderr, "Invoking:\n");
- for (i = 0; argv[i]; i++) {
- fprintf(stderr, "%s\n", argv[i]);
- }
- }
-
- /*
- FIXME: using fork_process here hangs the new xdvi process when it tries
- printing to stderr, so we use plain fork/exec (see comments in util.c)
- */
-#if 0
- fork_process(argv[0], False, NULL, NULL, NULL, 0, argv);
-#else
- {
- int pid;
- switch (pid = fork()) {
- case -1:
- perror("fork");
- case 0:
- execvp(argv[0], (char **)argv);
- XDVI_ERROR((stderr, "%s: Execution of %s failed.", globals.program_name, argv[0]));
- _exit(EXIT_FAILURE);
- default:
- FREE(shrink_arg);
- }
- }
-#endif
-#undef ARG_LEN
-}
-
-#if COPY_TMP_FILE
-/* callback to remove temporary file after helper application has terminated.
- Currently unused. Note the possible danger of a temp race if the application
- does an fclose() on the file before ...
-*/
-static void
-remove_temp_file(int status, struct xchild *this)
-{
- char *pathname = (char *)this->data;
- if (WEXITSTATUS(status) == 0) {
- unlink(pathname);
- }
- else {
- popup_message(globals.widgets.top_level,
- MSG_WARN, NULL,
- "Warning: Calling `%s' on `%s' terminated with non-zero status (%d)"
- "\n(Not removing `%s')",
- this->name, pathname, status, pathname);
- }
- free(pathname);
-}
-#endif
-
-void
-launch_program(const char *filename)
-{
- const char *format_string = NULL;
- char *content_type = NULL;
- char *viewer = NULL;
- char *argv[4];
- struct stat statbuf;
- const char *local_filename_sans_prefix;
- char *path, *syscmd, *tmp;
-#if COPY_TMP_FILE
- int tmp_fd;
-#endif
- const char *ptr;
- char *fullpath = NULL;
- char canonical_path[MAXPATHLEN + 1];
- Boolean needs_terminal;
- size_t offset;
-
- TRACE_HTEX((stderr, "launch_program called with |%s|", filename));
-
- /* is it a local file? */
- local_filename_sans_prefix = is_local_file(filename);
- if (local_filename_sans_prefix == NULL) { /* not local */
- launch_browser(filename);
- return;
- }
-
- /* expand the filename if it contains a relative path */
- path = find_file(local_filename_sans_prefix, &statbuf, kpse_program_text_format);
- if (path != NULL) {
- /* fully canonicalize path before passing it to helper applications */
- fullpath = REALPATH(path, canonical_path);
- if (fullpath == NULL) {
- XDVI_WARNING((stderr, "Couldn't canonicalize %s to full path - returning unexpanded.",
- path));
- fullpath = path;
- }
- else
- FREE(path);
- }
- else {
- XDVI_WARNING((stderr, "Couldn't find file %s; passing to application unchanged.",
- local_filename_sans_prefix));
- /* if it doesn't exist, maybe the user has encoded some magic in the
- filename; in that case, pass it to the application unchanged. */
- fullpath = (char *)local_filename_sans_prefix;
- }
-
- TRACE_HTEX((stderr, "fullpath: |%s|", fullpath));
- content_type = figure_mime_type(fullpath);
- ASSERT(content_type != NULL, "figure_mime_type() should have returned a valid type (eventually a fallback)");
-
- /* make it safe to pass the argument to system() or `sh -c',
- by escaping all `dangerous' characters: */
- tmp = shell_escape_string(fullpath);
- fullpath = tmp;
-
- if ((viewer = figure_viewer(content_type, &format_string, &needs_terminal, fullpath)) == NULL) {
- /* warn user if no application has been found. Help text needs to be constructed at
- run-time, since we want the correct content-type in it. */
-#if 0
- char *helptext = NULL;
-#else
- char *helptext = get_string_va("Please assign an application to the "
- "MIME type `%s' in your ~/.mailcap file. "
- "E.g. if you want to view the file with firefox, "
- "add the following line to your ~/.mailcap:\n"
- "%s; firefox '%%s'\n\n",
- content_type, content_type);
-#endif
- popup_message(globals.widgets.top_level,
- MSG_WARN,
- helptext,
- "Could not determine an application for the file %s, MIME type `%s'.",
- fullpath, content_type);
- /* FIXME: We can't free helptext here, because it won't be used until
- * the popup comes up and the user clicks on "Help". This doesn't
- * happen until after this function returns. */
- /* free(helptext); */
- free(fullpath);
- return;
- }
-
-#if COPY_TMP_FILE
- /* copy the file to a temporary location before passing it to the
- viewer. This is e.g. how Acroread does it. This should fix the
- problem with xdvizilla without -no-rm for DVI files (see comment
- in figure_viewer(), mime.c).
- SU 2003/10/02: currently I can't reproduce the xdvizilla problem
- any more - it seems that for xdvi files, argv[0] will be invoked
- anyway? Also, copying the files to tmp may break figure locations
- and relative links for DVI files. Suspended this for the time being.
- */
- tmp = NULL;
- if ((tmp_fd = xdvi_temp_fd(&tmp)) == -1) {
- XDVI_ERROR((stderr, "couldn't create temporary file; not calling helper application."));
- return;
- }
- TRACE_HTEX((stderr, "copying to temporary location: |%s->%s|", fullpath, tmp));
- if (!copy_file(fullpath, tmp)) {
- XDVI_ERROR((stderr, "couldn't copy %s to temporary file %s; not invoking helper application.",
- fullpath, tmp));
- return;
- }
- free(fullpath);
- fullpath = tmp;
-#endif
-
- if (strlen(format_string) > 0) {
- ptr = find_format_str(viewer, format_string);
- }
- else {
- /*
- Contrary to RFC 1343, we don't pass stuff via pipes (too bothersome).
- Instead, pass it as normal argument by appending it to the command.
- */
- ptr = strchr(viewer, '\0');
- }
-
- offset = 0;
- if (needs_terminal) {
- offset += strlen("xterm -e ");
- }
- /* allocate extra byte for optional whitespace after viewer command */
- syscmd = xmalloc(offset + strlen(viewer) + strlen(fullpath) + 2);
- if (needs_terminal) {
- strcpy(syscmd, "xterm -e ");
- }
- /* viewer command */
- memcpy(syscmd + offset, viewer, ptr - viewer);
- /* bugfix for #2931447: add space separator after viewer command if no format string is present */
- if (strlen(format_string) == 0) {
- strcpy(syscmd + offset + (ptr - viewer), " ");
- offset += 1;
- }
- /* viewer argument */
- strcpy(syscmd + offset + (ptr - viewer), fullpath);
- /* rest of command */
- strcpy(syscmd + offset + (ptr - viewer) + strlen(fullpath), ptr + strlen(format_string));
-
- /*
- mailcap(5) says that the mailcap command shall be passed to system(),
- so we musn't use fork_process() directly here. Instead, we pass the command
- to `/bin/sh -c', but via fork_process so that
-
- - xdvi doesn't hang if the process doesn't return;
- - we can still catch the return value if `sh -c' exits with an error
- (e.g. if the viewer command is not found).
-
- Note however that this doesn't mimick most of POSIX's system() semantics.
- */
- TRACE_HTEX((stderr, "execv(\"/bin/sh -c %s\")", syscmd));
- argv[0] = "/bin/sh";
- argv[1] = "-c";
- argv[2] = syscmd;
- argv[3] = NULL;
-#if COPY_TMP_FILE
- fork_process("/bin/sh", False, globals.dvi_file.dirname, remove_temp_file,
- fullpath, 0, argv);
-#else
- fork_process("/bin/sh", False, globals.dvi_file.dirname, NULL,
- NULL, 0, argv);
-#endif
-
- FREE(viewer);
-#if COPY_TMP_FILE
-#else
- FREE(fullpath);
-#endif
- FREE(syscmd);
-}
-
-void
-htex_set_anchormarker(int y)
-{
- Position drawing_x;
-
- /* erase old marker if it's on the same page as the new marker, after
- cancelling the old timeout so that it won't affect the new marker */
- if (m_href_timeout_id)
- XtRemoveTimeOut(m_href_timeout_id);
- htex_erase_anchormarker(NULL, NULL);
- XFlush(DISP);
-
- XtVaGetValues(globals.widgets.draw_widget, XtNx, &drawing_x, NULL);
- g_anchormarker.page = current_page;
- free(g_anchormarker.filename);
- g_anchormarker.filename = xstrdup(globals.dvi_name);
- g_anchormarker.y_pos = y;
- g_anchormarker.x_pos = DEFAULT_MARKER_X_OFFSET + -drawing_x;
- m_href_timeout_id = XtAppAddTimeOut(globals.app, STATUS_SHORT * 1000, htex_erase_anchormarker, (XtPointer)NULL);
-}
-
-static void
-htex_draw_anchormarker(int y)
-{
- int x;
- XPoint points[3];
-
- Position drawing_x, clip_w;
-
- XtVaGetValues(globals.widgets.clip_widget, XtNwidth, &clip_w, NULL);
- XtVaGetValues(globals.widgets.draw_widget, XtNx, &drawing_x, NULL);
-
- /* compute offset to draw into visible region */
- x = DEFAULT_MARKER_X_OFFSET + -drawing_x;
-
- /* Eventually erase old marker, to avoid `smearing' on horizontal scrolls. */
- if (x != g_anchormarker.x_pos) {
- clearexpose(&mane, g_anchormarker.x_pos - 1, y - 3, 20, 10);
- }
- g_anchormarker.x_pos = x;
-
- points[0].x = x + 10;
- points[1].x = x + 19;
- points[2].x = x + 10;
- points[0].y = y - 3;
- points[1].y = y + 2;
- points[2].y = y + 7;
-
- XFillRectangle(DISP, mane.win, globals.gc.visited_linkcolor, x, y, 10, 4);
- XFillPolygon(DISP, mane.win, globals.gc.visited_linkcolor, points, 3, Convex, CoordModeOrigin);
- /* -1 indicates that no horizontal scrolling is wanted, since the
- anchormarker will always be horizontally positioned inside the
- visible area.
- */
- scroll_page_if_needed(-1, -1, y + 3, y - 3);
-}
-
-
-static void
-htex_erase_anchormarker(XtPointer client_data, XtIntervalId *id)
-{
- Position clip_w;
-
- UNUSED(client_data);
- UNUSED(id);
-
- if (globals.debug & DBG_EVENT) {
- fprintf(stderr, "htex_erase_anchormarker called!\n");
- }
-
- if (m_href_timeout_id == (XtIntervalId)0) { /* timeout was removed but callback happened anyway */
- return;
- }
-
- m_href_timeout_id = (XtIntervalId)0;
- /* clear the mark if we're in the same file and on the same page as the mark */
- if (g_anchormarker.filename != NULL
- && strcmp(globals.dvi_name, g_anchormarker.filename) == 0
- && g_anchormarker.page == current_page) {
- XtVaGetValues(globals.widgets.clip_widget, XtNwidth, &clip_w, NULL);
- clearexpose(&mane, 0, g_anchormarker.y_pos - 3, clip_w, 10);
- }
- g_anchormarker.y_pos = -1;
-}
-