diff options
Diffstat (limited to 'Build/source/texk/windvi/hypertex.c')
-rw-r--r-- | Build/source/texk/windvi/hypertex.c | 1349 |
1 files changed, 1349 insertions, 0 deletions
diff --git a/Build/source/texk/windvi/hypertex.c b/Build/source/texk/windvi/hypertex.c new file mode 100644 index 00000000000..21128837307 --- /dev/null +++ b/Build/source/texk/windvi/hypertex.c @@ -0,0 +1,1349 @@ +/* + * 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. + * + * + * Note: several coordinate systems are in use in this code. Note + * that the relation between a screen pixel and a dvi coordinate is + * the current shrink factor times 2^16. + * + * When multiple pages are allowed in one drawing area, the variables + * xscroll_pages or yscroll_pages are set. + * + * Conversion between coordinates is done using the screen_to_page, + * page_to_screen, screen_to_abs, abs_to_screen routines. + +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 ANYONE ELSE 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. + +*/ + +#define HAVE_BOOLEAN +#include "xdvi-config.h" +#if defined(XHDVI) || defined(HTEX) +#include <kpathsea/c-pathch.h> +#include <kpathsea/c-ctype.h> +#include <kpathsea/c-fopen.h> +#include <kpathsea/c-stat.h> +#define GETCWD(str,size) xgetcwd() +#ifndef WIN32 +#include <X11/Shell.h> /* needed for def of XtNtitle */ +#include <X11/StringDefs.h> +#endif + +#ifdef WIN32 +#include <shellapi.h> +#include "winhtex.h" +#else +#include "wwwconf.h" +#include "WWWLib.h" +#include "WWWInit.h" +#include "WWWCache.h" + +#if 0 /* seems unnecessary?! */ +#ifdef HAVE_NETDB_H +#include <netdb.h> /* for struct hostent */ +#endif +#endif /* seems unnecessary?! */ +#endif /* !WIN32 */ + +/* Implementation of HyperTeX through \specials */ +/* One option: allow HTML tags and recognize them */ +/* applicationDoSpecial strips leading blanks, so first char should + be '<' if it's a tag */ + +char *MyStrAllocCopy(); +char *refscan(); +extern void put_rule(); +extern void make_absolute (); +extern int invokeviewer (); + +static void extractbase (); +static void retitle (); + +int this_is_a_href=0; + +#define HTeX_A_NAME 1 +#define HTeX_A_HREF 2 + +#define htex_shrinkfactor mane.shrinkfactor /* Only main win has refs */ + +typedef struct { + int type; /* Type of anchor: URL, etc from WWW anchor list */ + char *name; /* Name string for anchor (Null by default) */ + char *href; /* A reference from this anchor */ + int llx, lly, urx, ury; /* Box on page where anchor located */ +} HTeX_Anchor; + +/* Structure to remember where we have been: */ +typedef struct { + char *refname; /* File name (or href?) */ + int pageno; /* Which page anchor was on */ + int x,y; /* Approximate location on page... */ + int which; /* Number of anchor on this page */ + int type; /* And the other properties of this anchor */ + char *name; + char *href; +} Anchors; + +int waiting_for_anchor = -1; /* If waiting for anchor to be properly parsed? */ +int cur_anchor_on_page; /* Keep track of current page as it's read in */ + +#define HTeX_AnchorSTEP 20 +HTeX_Anchor **HTeX_anchorlist = NULL; +int *nHTeX_anchors, *maxHTeX_anchors; + +Anchors *HTeX_visited = NULL; +int nHTeX_visited = 0, maxHTeX_visited = 0; + +#define HTeX_NSTACK 32 +int HTeXAnest[HTeX_NSTACK]; /* Maximum number of nested anchors */ +int HTeXAnestlevel; /* Current nesting level */ + +int HTeXreflevel; /* 0 if not currently inside an href anchor */ + +int *htex_parsedpages = NULL; /* List of all pages, = 1 if already parsed, zero if not */ +int htex_total_pages; +/* size = total_pages, current page = current_page defined in xhdvi.h */ + +void htex_parseanchor ARGS((char *, HTeX_Anchor *)); +char *MyStrAllocCopy ARGS((char **, char *)); +char *refscan ARGS(( char*, char **, char **)); +void htex_loc_on_page ARGS((Anchors *)); +void freeHTeXAnchors ARGS((HTeX_Anchor *, int)); +void htex_img ARGS((int, char *, int)); +void htex_base ARGS((int, char *, int)); + +#define BEGIN 0 +#define END 1 + +/* Dave Oliver's hypertex format: */ +/* Only understand my version of anchors so far */ +/* ie.: his TYPE=text for hrefs, frag for names */ +void +hy_handletag(cp, pageno) + char *cp; + int pageno; +{ + int beginend=BEGIN; + + while (isspace(*cp)) cp++; + if (!strncasecmp(cp, "END", 3)) { + beginend = END; + cp += 3; + } +/* Leave the parsing to htex_anchor! */ + htex_anchor(beginend, cp, pageno); +} + +int +checkHyperTeX(cp, pageno) +char *cp; +int pageno; +{ + int htexfound = 0; + + if (strncasecmp(cp, "html:", 5) == 0) { + cp += 5; + while (isspace(*cp)) cp++; + htexfound = 1; + } + if (*cp == '<') { /* Possibly Missing the header part */ + htexfound = 1; + htex_handletag(cp, pageno); + } else if (strncasecmp(cp, "hyp", 3) == 0) { + /* Dave Oliver's HyperTeX */ + htexfound = 1; + cp += 4; + hy_handletag(cp, pageno); + } + + return htexfound; +} + +void +htex_handletag(cp, pageno) +char *cp; +int pageno; +{ + int beginend=BEGIN; + + if (*cp != '<') return; + ++cp; + while (isspace(*cp)) cp++; + if (*cp == '/') { + beginend = END; + cp++; + } + switch(*cp) { + case 'A': + case 'a': /* Anchors */ + htex_anchor(beginend, cp+1, pageno); + break; + case 'b': /* Base name? */ + htex_base(beginend, cp, pageno); + break; + case 'i': /* Included images? */ + htex_img(beginend, cp, pageno); + break; + default: /* Tag not implemented yet */ + break; + } +} + +/* Basically just want to parse the line... */ +/* Should use WWW library stuff ? */ + +void +htex_anchor(beginend, cp, pageno) +int beginend, pageno; +char *cp; +{ + int *nap, *maxp; + int oldllx, oldlly, oldurx, oldury; + HTeX_Anchor *HTeXAp, **HTeXApp; + + HTeXApp = HTeX_anchorlist + pageno; + nap = nHTeX_anchors + pageno; + maxp = maxHTeX_anchors + pageno; + if (*HTeXApp == NULL) { + *maxp = HTeX_AnchorSTEP; + *HTeXApp = xmalloc((*maxp)*sizeof(HTeX_Anchor)); + } else if (*nap == *maxp) { + *maxp += HTeX_AnchorSTEP; + *HTeXApp = (HTeX_Anchor *) realloc(*HTeXApp, + (*maxp)*sizeof(HTeX_Anchor)); + } + if (htex_parsedpages[pageno] != 1) { /* Only do if page not done yet */ + if (beginend == END) { + HTeXAnestlevel--; + if (HTeXAnestlevel < 0) { + HTeXAnestlevel = 0; /* Extra </a>'s? */ + } else { + HTeXAp = *HTeXApp + HTeXAnest[HTeXAnestlevel]; + if (HTeXAp->llx > DVI_H) { + HTeXAp->llx = DVI_H; + } + if (HTeXAp->urx < DVI_H) { + HTeXAp->urx = DVI_H; + } + if (HTeXAp->lly > DVI_V) { + HTeXAp->lly = DVI_V; + } + if (HTeXAp->ury < DVI_V) { + HTeXAp->ury = DVI_V; + } + oldllx = HTeXAp->llx; + oldlly = HTeXAp->lly; + oldurx = HTeXAp->urx; + oldury = HTeXAp->ury; + if (debug & DBG_ANCHOR) { + Printf("Added anchor %d, level %d:\n", + HTeXAnest[HTeXAnestlevel], HTeXAnestlevel); + if (HTeXAp->type&HTeX_A_HREF) { + Printf("href = %s\n", HTeXAp->href); + } + if (HTeXAp->type&HTeX_A_NAME) { + Printf("name = %s\n", HTeXAp->name); + } + Printf("box %d %d %d %d\n", + HTeXAp->llx, HTeXAp->lly, HTeXAp->urx, HTeXAp->ury); + } + if (waiting_for_anchor == HTeXAnest[HTeXAnestlevel]) { + htex_to_anchor(current_page, waiting_for_anchor); + waiting_for_anchor = -1; /* Reset it! */ + } + /* End of debug section */ + if (HTeXAnestlevel > 0) { + HTeXAp = *HTeXApp + HTeXAnest[HTeXAnestlevel-1]; + /* Check llx, lly, urx, ury info */ + if (oldllx < HTeXAp->llx) { + HTeXAp->llx = oldllx; + } + if (oldlly < HTeXAp->lly) { + HTeXAp->lly = oldlly; + } + if (oldurx > HTeXAp->urx) { + HTeXAp->urx = oldurx; + } + if (oldury > HTeXAp->ury) { + HTeXAp->ury = oldury; + } + } + } + } else { + HTeXAp = *HTeXApp + *nap; + /* Set type, and the name, href */ + htex_parseanchor(cp, HTeXAp); + if (HTeXAp->type != 0) { + cur_anchor_on_page++; /* Increment the count of anchors here */ + if (htex_parsedpages[pageno] == 2) { + /* Go to this anchor in list we already have: */ + HTeXAp = *HTeXApp + cur_anchor_on_page; + HTeXAp->urx = HTeXAp->llx = DVI_H; /* Current horiz pos.*/ + HTeXAp->ury = HTeXAp->lly = DVI_V; /* Current vert. pos. */ + if (HTeXAnestlevel >= HTeX_NSTACK) { + /* Error - too many nested anchors! */ + } else { + HTeXAnest[HTeXAnestlevel++] = cur_anchor_on_page; + } + } else if (htex_parsedpages[pageno] != 1) { /* Only do if page not done yet */ + HTeXAp->urx = HTeXAp->llx = DVI_H; /* Current horiz pos.*/ + HTeXAp->ury = HTeXAp->lly = DVI_V; /* Current vert. pos. */ + if (HTeXAnestlevel >= HTeX_NSTACK) { + /* Error - too many nested anchors! */ + } else { + HTeXAnest[HTeXAnestlevel++] = *nap; + } + (*nap)++; + } + } + } + } else { /* if page has been properly parsed before */ + if (beginend != END) { + HTeXAp = *HTeXApp + *nap; + /* Set type, and the name, href */ + htex_parseanchor(cp, HTeXAp); + } + } + if (beginend == END) { + if (HTeXreflevel > 0) HTeXreflevel--; + } else { + if (HTeXAp->type&HTeX_A_HREF) HTeXreflevel++; + } +} + +void +htex_initpage() /* Starting a new page */ +{ + if (htex_parsedpages == NULL) htex_reinit(); + HTeXAnestlevel = 0; /* Start with zero nesting level for a page */ + HTeXreflevel = 0; + HTeXnext_extern = 0; /* Go to links in current window */ + cur_anchor_on_page = -1; + paint_anchor(NULL); +} + +/* A character or something was written: record position for current anchor */ +void +htex_recordbits(x, y, w, h) /* x,y are pixel positions on current page */ +int x, y, w, h; +{ + HTeX_Anchor *HTeXAp; + int dvix, dviy, dvix2, dviy2; + int ch = 0; + + dvix = x *(htex_shrinkfactor << 16); + dviy = y*(htex_shrinkfactor << 16); + dvix2 = (x+w)*(htex_shrinkfactor << 16); + dviy2 = (y+h)*(htex_shrinkfactor << 16); + HTeXAp = HTeX_anchorlist[current_page] + HTeXAnest[HTeXAnestlevel-1]; + if (HTeXAp->llx > dvix) { + HTeXAp->llx = dvix; + ch++; + } + if (HTeXAp->lly > dviy) { + HTeXAp->lly = dviy; + ch++; + } + if (HTeXAp->urx < dvix2) { + HTeXAp->urx = dvix2; + ch++; + } + if (HTeXAp->ury > dviy2) { + HTeXAp->ury = dviy2; + ch++; + } + if (debug & DBG_ANCHOR) { + if (ch > 0) { + Printf("New box for anchor %d, level %d: %d %d %d %d\n", + HTeXAnest[HTeXAnestlevel-1], HTeXAnestlevel, + HTeXAp->llx, HTeXAp->lly, HTeXAp->urx, HTeXAp->ury); + } + } +} + +void +htex_donepage(i, pflag) /* This page has been completed */ +int i, pflag; +{ + HTeX_Anchor *HTeXAp; + + /* Finish off boxes for nested anchors not done on this page */ + while (HTeXAnestlevel > 0) { + HTeXAnestlevel--; + HTeXAp = HTeX_anchorlist[i] + HTeXAnest[HTeXAnestlevel]; + if (HTeXAp->llx > DVI_H) { + HTeXAp->llx = DVI_H; + } + if (HTeXAp->urx < DVI_H) { + HTeXAp->urx = DVI_H; + } + if (HTeXAp->lly > DVI_V) { + HTeXAp->lly = DVI_V; + } + if (HTeXAp->ury < DVI_V) { + HTeXAp->ury = DVI_V; + } + } + if (pflag == 1) { /* Really parsed this page */ + htex_drawboxes(); /* Draw boxes around the anchor positions */ + htex_parsedpages[i] = 1; + } else { + htex_parsedpages[i] = 2; /* Means htex_parsed, not done properly */ + } +} + +/* If the dvi file has changed, assume all links have changed also, + and reset everything! */ +void +htex_reinit() +{ + int i; + + if (htex_parsedpages == NULL) { /* First call to this routine */ + htex_parsedpages = xmalloc(total_pages*sizeof(int)); + HTeX_anchorlist = xmalloc(total_pages*sizeof(HTeX_Anchor *)); + nHTeX_anchors = xmalloc(total_pages* sizeof(int)); + maxHTeX_anchors = xmalloc(total_pages* sizeof(int)); + for (i=0; i < total_pages; i++) maxHTeX_anchors[i] = 0; + } else if (htex_total_pages != total_pages) { + htex_parsedpages = (int *) realloc(htex_parsedpages, + total_pages*sizeof(int)); + /* Following operates if new has fewer pages than old: */ + for (i=total_pages; i < htex_total_pages; i++) { + if (maxHTeX_anchors[i] > 0) + freeHTeXAnchors(HTeX_anchorlist[i], nHTeX_anchors[i]); + } + HTeX_anchorlist = (HTeX_Anchor **) realloc(HTeX_anchorlist, + total_pages*sizeof(HTeX_Anchor *)); + nHTeX_anchors = (int *) realloc(nHTeX_anchors, + total_pages* sizeof(int)); + maxHTeX_anchors = (int *) realloc(maxHTeX_anchors, + total_pages* sizeof(int)); + /* Following operates if new has more pages than old: */ + for (i= htex_total_pages; i < total_pages; i++) + maxHTeX_anchors[i] = 0; + } + htex_total_pages = total_pages; + for (i=0; i < total_pages; i++) { + htex_parsedpages[i] = 0; + if (maxHTeX_anchors[i] > 0) { /* Get rid of the old anchor lists: */ + freeHTeXAnchors(HTeX_anchorlist[i], nHTeX_anchors[i]); + free(HTeX_anchorlist[i]); + } + HTeX_anchorlist[i] = NULL; + nHTeX_anchors[i] = 0; + maxHTeX_anchors[i] = 0; + } +} + +/* Following parses the stuff after the '<' in the html tag */ +/* Only understands name and href in anchor */ +/* html: <A HREF="..." NAME="..."> */ +/* html: <A NAME="..." HREF="...> */ +void +htex_parseanchor(cp, anchor) +char *cp; +HTeX_Anchor *anchor; +{ + char *ref, *str; + + anchor->type = 0; + anchor->href = NULL; + anchor->name = NULL; + while (isspace(*cp)) cp++; + while ((*cp) && (*cp != '>')) { + cp = refscan(cp, &ref, &str); + if (cp == NULL) break; + if (strcasecmp(ref, "href") == 0) { + anchor->type |= HTeX_A_HREF; + MyStrAllocCopy(&(anchor->href), str); + } else if (strcasecmp(ref, "name") == 0) { + anchor->type |= HTeX_A_NAME; + MyStrAllocCopy(&(anchor->name), str); + } + } +} + +char *MyStrAllocCopy(dest, src) +char **dest, *src; +{ + if (*dest) free(*dest); + if (! src) + *dest = NULL; + else { + *dest = xmalloc(strlen(src) + 1); + strcpy(*dest, src); + } + return *dest; +} + +/* Parses cp containing 'ref="string"more', returning pointer to "more" */ +char *refscan(name, ref, str) +char *name, **ref, **str; +{ + char *cp; + + *str = name; + for (cp=name; *cp; cp++) { + if (*cp == '=') { + *cp = 0; + *ref = name; + *str = cp+1; + break; + } + } + cp = *str; + if (cp != name) { + while (isspace(*cp)) cp++; + if (*cp == '"') { /* Yes, this really is a string being set */ + *str = cp+1; + while ((cp = strchr(cp+1, '"')) != NULL) { + if (cp[-1] != '\\') break; /* Check if quote escaped */ + } + if (cp != NULL) { + *cp = 0; + cp++; + } + } else { + cp = NULL; + } + } else { + cp = NULL; + } + return cp; +} + +/* What happens when mouse moves on screen: */ +void +htex_displayanchor(page, x, y) +int page, x, y; /* x,y coordinates of mouse position */ +{ + char astr[256]; + char namestr[256]; + char hrefstr[256]; + HTeX_Anchor *HTeXAp; + long dvix, dviy; + int i; + +/* Don't display until we've finished with the page: */ + if (htex_parsedpages == NULL) return; +/* Locate current page if we're scrolling them: */ + current_page = page; + if (htex_parsedpages[current_page] != 1) return; + dvix = x *(htex_shrinkfactor << 16); + dviy = y *(htex_shrinkfactor << 16); + /* Find anchor that fits current position: */ + HTeXAp = HTeX_anchorlist[current_page] + nHTeX_anchors[current_page] - 1; + for (i=nHTeX_anchors[current_page] - 1; i >= 0; i--, HTeXAp--) { + if (HTeXAp->llx > dvix) continue; + if (HTeXAp->lly > dviy) continue; + if (HTeXAp->urx < dvix) continue; + if (HTeXAp->ury < dviy) continue; + if (debug & DBG_ANCHOR) { + Printf("In anchor #%d\n", i); + } + if (HTeXAp->type & HTeX_A_NAME) { + sprintf(namestr, "name = %s ", HTeXAp->name); + } else { + *namestr= 0; + } + if (HTeXAp->type & HTeX_A_HREF) { + sprintf(hrefstr, "href = %s ", HTeXAp->href); + } else { + *hrefstr = 0; + } + sprintf(astr, "anchor #%d: %s%s", i, namestr, hrefstr); + paint_anchor(astr); + break; + } + if (i == -1) paint_anchor(NULL); +} + +/* What happens when mouse is clicked: */ +int +htex_handleref(page, x, y) + int page, x, y; /* current mouse location when ref clicked */ +{ + HTeX_Anchor *HTeXAp; + long dvix, dviy; + int i, afound; + +/* Check that we've finished at least one page first! */ + if (htex_parsedpages == NULL) return 0; +/* Locate current page if we're scrolling them: */ + current_page = page; + if (htex_parsedpages[current_page] != 1) return 0; + dvix = x *(htex_shrinkfactor << 16); + dviy = y *(htex_shrinkfactor << 16); + /* Find anchor that fits current position: */ + HTeXAp = HTeX_anchorlist[current_page] + nHTeX_anchors[current_page] - 1; + afound = -1; +#if 0 + fprintf(stderr, "click @ (%d, %d)\n", x, y); +#endif + for (i=nHTeX_anchors[current_page]-1; i >= 0; i--, HTeXAp--) { + if ((HTeXAp->type&HTeX_A_HREF) == 0) continue; /* Only ref on hrefs */ +#if 0 + fprintf(stderr, "Href @ (%d, %d) -- (%d, %d)\n", + (int)(HTeXAp->llx / (htex_shrinkfactor << 16)), + (int)(HTeXAp->lly / (htex_shrinkfactor << 16)), + (int)(HTeXAp->urx / (htex_shrinkfactor << 16)), + (int)(HTeXAp->ury / (htex_shrinkfactor << 16))); +#endif + if (HTeXAp->llx > dvix) continue; + if (HTeXAp->lly > dviy) continue; + if (HTeXAp->urx < dvix) continue; + if (HTeXAp->ury < dviy) continue; + afound = i; /* Get the last of them in case of nesting */ + break; + } + if (afound == -1) return 0; /* There was no href at this location */ +/* Then just do it: */ + this_is_a_href=1; + htex_dohref(HTeXAp->href); + this_is_a_href=0; + return 1; +} + +void +htex_dohref(href) + char *href; +{ + int i; + +/* Update the list of where we used to be: */ + if (HTeX_visited == NULL) { + maxHTeX_visited = HTeX_AnchorSTEP; + HTeX_visited = xmalloc(maxHTeX_visited*sizeof(Anchors)); + for (i=0; i < maxHTeX_visited; i++) { + HTeX_visited[i].refname = NULL; + HTeX_visited[i].name = NULL; + HTeX_visited[i].href = NULL; + } + } else if (nHTeX_visited >= maxHTeX_visited - 1) { + maxHTeX_visited += HTeX_AnchorSTEP; + HTeX_visited = (Anchors *) realloc(HTeX_visited, + maxHTeX_visited*sizeof(Anchors)); + for (i=nHTeX_visited; i < maxHTeX_visited; i++) { + HTeX_visited[i].refname = NULL; + HTeX_visited[i].name = NULL; + HTeX_visited[i].href = NULL; + } + } + MyStrAllocCopy(&(HTeX_visited[nHTeX_visited].refname), dvi_name); + HTeX_visited[nHTeX_visited].pageno = current_page; +#ifdef HTEX + HTeX_visited[nHTeX_visited].x = mane.base_x; + HTeX_visited[nHTeX_visited].y = mane.base_y; +#else + HTeX_visited[nHTeX_visited].x = mane.base_ax; + HTeX_visited[nHTeX_visited].y = mane.base_ay; +#endif + HTeX_visited[nHTeX_visited].type = HTeX_A_HREF; + HTeX_visited[nHTeX_visited].which = 0; + MyStrAllocCopy(&(HTeX_visited[nHTeX_visited].href), href); + nHTeX_visited++; + if (htex_is_url(href)) htex_do_url(href); + else htex_do_loc(href); + /* Need to handle properly when ref doesn't exist! */ +} + +/* Draw boxes around the anchor positions */ +void htex_drawboxes() +{ + HTeX_Anchor *HTeXAp; + int i; + int x, y, w, h; + + if (!underline_link) return; + HTeXAp = HTeX_anchorlist[current_page]; + for (i=0; i < nHTeX_anchors[current_page]; i++, HTeXAp++) { + if ((HTeXAp->type&HTeX_A_HREF) == 0) continue; /* Only box hrefs */ + x = pixel_conv(HTeXAp->llx)-1; + y = pixel_conv(HTeXAp->lly)-1; + w = pixel_conv(HTeXAp->urx) - x+2; + h = pixel_conv(HTeXAp->ury) - y+2; +/* The last arg of put_rule is whether or not to + use the "highlight" graphics context. */ +#ifdef HTEX + highlight = True; + put_rule(x+1, y+h, w, 1); + highlight = False; +#else +/* put_rule(x, y, w, 1, True); + put_rule(x+w, y, 1, h, True); */ + put_rule(x+1, y+h, w, 1, True); +/* put_rule(x, y+1, 1, h, True); */ +#endif + } +} +#ifdef WIN32 +RECT WinRect; +extern HWND hWndMain; +#else +static Arg arg_wh[] = { + {XtNwidth, (XtArgVal) &window_w}, + {XtNheight, (XtArgVal) &window_h}, +}; +#endif +static void +invokedviviewer(filename, aname, height) + char *filename; + char *aname; + int height; +{ + char buf[1024]; + + if (filename == NULL) return; +#if 0 + /* Ignore the given height -- some calls use unreasonable values. */ + if (height < 50) height = 50; + height += 50; +#endif + +#ifdef WIN32 + GetWindowRect(hWndMain, &WinRect); + window_w = WinRect.right - WinRect.left; + window_h = WinRect.bottom - WinRect.top; +#else + XtGetValues(draw_widget, arg_wh, XtNumber(arg_wh)); +#endif + if (aname == NULL) { + sprintf(buf, "%s %s -geometry %dx%d", program_invocation_name, + filename, + window_w, window_h); /* Same width and height */ + } else { + sprintf(buf, "%s %s#%s -geometry %dx%d", program_invocation_name, + filename, aname, + window_w, window_h); /* Same width and height */ + } +#ifndef WIN32 + strcat(buf, " &"); +#endif + if (debug & DBG_HYPER) { + fprintf(stderr, "Executing: %s\n", buf); + } + system(buf); +} + +/* It's a local reference - find the anchor and go to it */ +void +htex_do_loc(href) +char *href; +{ + int ipage, ia, reffound; + HTeX_Anchor *HTeXAp, **HTeXApp; + char astr[256]; + char *cp; + + if (href == NULL) return; /* shouldn't happen? */ + if (debug & DBG_HYPER) { + fprintf(stderr,"htex_do_url(%s)\n", href); + } + cp = href; + while (*cp == '#') cp++; + HTeXApp = HTeX_anchorlist; + reffound = 0; + /* Should hash based on "name" value? - to speed this up! */ + for (ipage = 0; ipage < total_pages; ipage++, HTeXApp++) { + if (htex_parsedpages[ipage] == 0) continue; + HTeXAp = *HTeXApp; + for (ia=0; ia < nHTeX_anchors[ipage]; ia++, HTeXAp++) { + if ((HTeXAp->type&HTeX_A_NAME) == 0) continue; + if (!strcmp(HTeXAp->name, cp)) { + reffound = 1; + break; + } + } + if (reffound) break; + } + if (reffound == 0) { /* Need to parse remaining pages */ + if (debug & DBG_ANCHOR) { + Printf("Searching for remaining anchors\n"); + } + htex_parsepages(); + /* And try again: */ + HTeXApp = HTeX_anchorlist; + for (ipage = 0; ipage < total_pages; ipage++, HTeXApp++) { + if (htex_parsedpages[ipage] < 2) continue; + HTeXAp = *HTeXApp; + for (ia=0; ia < nHTeX_anchors[ipage]; ia++, HTeXAp++) { + if ((HTeXAp->type&HTeX_A_NAME) == 0) continue; + if (!strcmp(HTeXAp->name, cp)) { + reffound = 1; + break; + } + } + if (reffound) break; + } + } + if (reffound) { + if (HTeXnext_extern == 1) { + invokedviviewer(dvi_name, cp, + pixel_conv(HTeXAp->ury) - pixel_conv(HTeXAp->lly)); + } else { + htex_to_anchor(ipage, ia); /* move to anchor */ + } + } else { + if ((nHTeX_visited == 0) || + (!strcmp(HTeX_visited[nHTeX_visited-1].refname, dvi_name))) { + /* Really was from same file - just print error message */ + sprintf(astr, "Error: reference \"%s\" not found\n", cp); + paint_anchor(astr); + } else { + /* Go to page 1 and print error message */ + sprintf(astr, "Error: reference \"%s\" in file %s not found\n", + cp, dvi_name); + htex_to_page(0); /* Go to first page! */ + paint_anchor(astr); + } + } +} + +void +htex_can_it() +{ +#ifdef WIN32 + redraw_page(); +#else + canit = True; + XFlush(DISP); +#endif +} + +void +htex_to_page(pageno) + int pageno; +{ + /* taken from keystroke subroutine: */ + current_page = pageno; + htex_can_it(); +} + +void +htex_to_anchor(pageno, n) + int pageno, n; +{ + int xp, yp; + HTeX_Anchor *HTeXAp = HTeX_anchorlist[pageno] + n; + + if ((n < 0) || (n >= nHTeX_anchors[pageno])) return; /* Error message for this? */ + if (pageno != current_page) { + if (htex_parsedpages[pageno] != 1) waiting_for_anchor = n; + /* taken from keystroke subroutine: */ + current_page = pageno; + htex_can_it(); + } + xp = (HTeXAp->llx + HTeXAp->urx)/(2*htex_shrinkfactor << 16); + yp = (HTeXAp->lly + HTeXAp->ury)/(2*htex_shrinkfactor << 16); + if (debug & DBG_ANCHOR) { + Printf("Moving to pixel %d %d\n", xp, yp); + } +#ifndef HTEX + if (htex_parsedpages[pageno] > 0) centerpage(pageno, xp, yp); +#endif +} + +/* Following goes back to previous anchor point */ +void +htex_goback() +{ + int i; + + if (nHTeX_visited <= 0) return; /* There's nowhere to go! */ + if (debug & DBG_ANCHOR) { + Printf("Currently %d anchors in sequence:\n", nHTeX_visited); + for (i=0; i < nHTeX_visited; i++) { + Printf("%d file %s, href=%s\n", i, + HTeX_visited[i].refname, HTeX_visited[i].href); + } + } + nHTeX_visited--; + if (strcmp(HTeX_visited[nHTeX_visited].refname, dvi_name) != 0) { + /* Need to read in old file again! */ + MyStrAllocCopy(&dvi_name, HTeX_visited[nHTeX_visited].refname); + i = URL_aware; + URL_aware = FALSE; + open_dvi_file(); + URL_aware = i; + if (dvi_file != NULL) { + retitle(dvi_name); + extractbase(dvi_name); + } else { + perror(dvi_name); + Exit(1); + } + htex_can_it(); + htex_reinit(); + } + htex_loc_on_page(HTeX_visited + nHTeX_visited); + /* taken from keystroke subroutine: */ + htex_can_it(); +} + +/* Is this a url we recognize? */ +int +htex_is_url(href) +const char *href; +{ + /* Why reinvent the wheel? Use libwww routines! */ + return (HTURL_isAbsolute(href)==YES ? 1 : 0); +} + + +#ifndef WIN32 +static Arg temp_args4[] = { + {XtNtitle, (XtArgVal) 0}, + {XtNinput, (XtArgVal) True}, +}; +#endif + +static void +retitle(str) /* Change the title to "str" */ +char *str; +{ +#ifdef WIN32 + SetWindowText(top_level, str); +#else + temp_args4[0].value = (XtArgVal) str; + XtSetValues(top_level, temp_args4, XtNumber(temp_args4)); +#endif +} + +/* Can handle href's of form file:?.dvi#name */ +/* Actually, supposedly we can handle anything now... */ +void +htex_do_url(href) +char *href; +{ + if (href == NULL) return; /* shouldn't happen? */ + if (debug & DBG_HYPER) { + fprintf(stderr,"htex_do_url(%s)\n", href); + } + + /* Have dvi_name parsed using libwww routines to make sure + it doesn't contain invalid characters. Actually, we may + assume that HTURL_isAbsolute(href) when this is called, + so parsing it relative to URLbase shouldn't matter. */ + +#ifdef WIN32 + if (dvi_name) + free(dvi_name); + dvi_name = HTParse(href, URLbase, PARSE_ALL); +#else + /* HTParse already allocates memory. This should be fixed. */ + if (URLbase != NULL) { + MyStrAllocCopy(&dvi_name, HTParse(href, URLbase, PARSE_ALL)); + } else { + MyStrAllocCopy(&dvi_name, HTParse(href, "", PARSE_ALL)); + } +#endif + URL_aware = TRUE; + detach_anchor(); + if (open_www_file() == 0) { + /* HTTP request was handled externally by invoking some viewer */ + URL_aware = FALSE; + htex_can_it(); + htex_goback(); /* Go back to where we were! */ + return; + } else { + /* HTTP request was handled internally by calling open_dvi_file() */ + URL_aware = FALSE; + /* retitle(dvi_name); */ + /* extractbase(dvi_name); */ + htex_reinit(); + if (anchor_name != NULL) { + /* This may be unnecessary, since it's already done in + check_for_anchor() which is called from draw_page(). */ + htex_do_loc(anchor_name); + free(anchor_name); + anchor_name = NULL; + } else { + /* This seems to be necessary if there's no anchor_name. */ + htex_to_page(0); + } + return; + } +} + +/* Find the anchor pointed to by ap on the given page */ + +void +htex_loc_on_page(ap) +Anchors *ap; +{ + if (htex_parsedpages[ap->pageno] == 0) { + htex_parse_page(ap->pageno); /* Parse the needed page! */ + } + htex_to_anchor(ap->pageno, ap->which); /* move to anchor i */ +} + +void +freeHTeXAnchors(HTeXAp, nHTeX) +HTeX_Anchor *HTeXAp; +int nHTeX; +{ + int i; + + for (i=0; i < nHTeX; i++) { + if (HTeXAp[i].type&HTeX_A_NAME) + free(HTeXAp[i].name); + if (HTeXAp[i].type&HTeX_A_HREF) + free(HTeXAp[i].href); + } +} + +/* Following shouldn't be necessary... */ +/* Add the string cp to the current search string */ +#define LINE 1024 +char anchor_search_string[LINE]; + +void +add_search(cp, n) +char *cp; +int n; +{ + int anchor_search_len = 0; + + while (n>0) { + switch(*cp) { + case '\v': + case '\f': + case '\r': + case '\n': /* Finish string and search on it */ + anchor_search_string[anchor_search_len] = '\0'; + if (anchor_search_len > 0) { + htex_dohref(anchor_search_string); + /* Need to handle properly when ref doesn't exist! */ + } + return; + break; + case '\b': + case '\177': /* Del */ + if (anchor_search_len > 0) anchor_search_len--; + break; + case '': + anchor_search_len = 0; + break; + default: + if (*cp > 10) { + anchor_search_string[anchor_search_len++] = *cp; + } + break; + } + cp++; + n--; + } + anchor_search_string[anchor_search_len] = '\0'; + if (debug & DBG_ANCHOR) { + Printf("Search string: %s\n", anchor_search_string); + } +} + +void +htex_base(beginend, cp, pageno) +int beginend, pageno; +char *cp; +{ + char *ref, *str; + if (beginend == END) return; + + if (!strncasecmp(cp, "base", 4)) { + cp += 4; + cp = refscan(cp, &ref, &str); + if (cp == NULL) return; + while (isspace(*ref)) ref++; + while (isspace(*str)) str++; + if (strcasecmp(ref, "href") == 0) { + cp = str + strlen(str) - 1; /* Fix end of anchor */ + while (isspace(*cp)) cp--; + if (*cp == '>') cp --; + while (isspace(*cp)) cp--; + cp++; + *cp = '\0'; + MyStrAllocCopy(&URLbase, str); /* Change base */ + if (debug & DBG_HYPER) { + Printf("Changing base name to: %s\n", URLbase); + } + } + } +} + +void +htex_img(beginend, cp, pageno) +int beginend, pageno; +char *cp; +{ + char *ref, *str; + char fullpathname[1024]; + + if (beginend == END) return; + if (pageno != current_page) return; /* Only do when on page */ + if (htex_parsedpages[pageno] == 1) return; /* And first time through */ + if (!strncasecmp(cp, "img", 3)) { + cp += 3; + cp = refscan(cp, &ref, &str); + if (cp == NULL) return; + while (isspace(*ref)) ref++; + while (isspace(*str)) str++; + if (strcasecmp(ref, "src") == 0) { + cp = str + strlen(str) - 1; /* Fix end of anchor */ + while (isspace(*cp)) cp--; + if (*cp == '>') cp --; + while (isspace(*cp)) cp--; + cp++; + *cp = '\0'; + strcpy(fullpathname, str); + make_absolute(fullpathname, URLbase, 1024); + if (invokeviewer(fullpathname) != 1) { + fprintf(stderr, "Don't know how to deal with <img src=%s>\n", fullpathname); + } + } + } +} + +#ifdef HTEX +#ifndef WIN32 +#undef exit /* just in case */ +void +htex_cleanup(arg) +int arg; +{ + /* Delete all the temp files we created */ + for (;nURLs>0; nURLs--) { + /* fprintf(stderr,"htex: Unlinking %s\n",filelist[nURLs-1].file); */ + unlink(filelist[nURLs-1].file); + } + HTCache_flushAll(); + HTProfile_delete(); +} +#endif /* !WIN32 */ +/* Extract the URL base name from initial file name */ +static void +extractbase(file) +char *file; +{ + char *cp; + static char *cwd = NULL; + int n; + + if (URLbase != NULL) { + free(URLbase); + URLbase = NULL; + } + + if (strrchr(file, '/') != NULL) { /* If no /'s then leave dir NULL */ + n = strlen(file); + if (htex_is_url(file)) { /* It already is a URL */ + URLbase = xmalloc((unsigned) (n+1)); + Sprintf(URLbase, "%s", file); + } else { /* Turn it into one: */ + cwd = GETCWD(cwd, 1024); + URLbase = xmalloc((unsigned) (n+6 + strlen(cwd))); + Sprintf(URLbase, "file:%s/%s", cwd, file); + } + cp = strrchr(URLbase, '/'); + if (cp == NULL) { + fprintf(stderr, "This should not happen!\n"); + free(URLbase); + URLbase = NULL; + return; + } +/* cp[1] = '\0'; */ /* Leave it alone */ + } +} + +void +detach_anchor() +{ + char *cp; + + cp = strchr(dvi_name, '#'); /* Handle optional # in name */ + if (cp != NULL) { + *cp = '\0'; /* Terminate filename string */ + cp++; + while (*cp == '#') cp++; + MyStrAllocCopy(&anchor_name, cp); +#ifdef WIN32 + /* FIXME : this is caused by some .dvi + added to the filename */ + if (strlen(anchor_name) >= 4 && + FILESTRCASEEQ(anchor_name+strlen(anchor_name)-4, + ".dvi")) { + anchor_name[strlen(anchor_name)-4] = '\0'; + } +#endif + } +} + +int +open_www_file() +{ + char *url = NULL; + +#ifndef WIN32 + atexit(htex_cleanup); +#endif + if (debug & DBG_HYPER) { + fprintf(stderr, "open_www_file(%s)\n", dvi_name); + } + + /* open_www_file() may be called from main() at program startup, in + which case we have to turn dvi_name into an absolute URL. */ + + if (URLbase && !HTURL_isAbsolute(dvi_name)) { + MyStrAllocCopy(&url, dvi_name); +#ifdef WIN32 + if (dvi_name) + free(dvi_name); + dvi_name = HTParse(url, "", PARSE_ALL); +#else + MyStrAllocCopy(&dvi_name, HTParse(url, "", PARSE_ALL)); +#endif + free(url); + } + + /* Otherwise, we're called with an absoulte URL in dvi_name, either + from main() or form htex_do_url(). In both cases detach_anchor() + has been called before open_www_file(). */ +#ifdef WIN32 + if (FILESTRNCASEEQ(dvi_name, "ftp:", 4) + || FILESTRNCASEEQ(dvi_name, "mailto:", 7) + || FILESTRNCASEEQ(dvi_name, "http:", 5) + || (strlen(dvi_name) > 5 + && FILESTRNCASEEQ(dvi_name, "file:", 5) + && !FILESTRCASEEQ(dvi_name + strlen(dvi_name) - 4, ".dvi"))) { + /* FIXME : this is a bit rough ! */ + ShellExecute(NULL, "open", dvi_name, NULL, NULL, SW_SHOWNORMAL); + return 0; + } +#else + + if (strcmp(figure_mime_type(dvi_name),"application/x-dvi")!=0) { + + /* Try other standard extensions: */ + if (!invokeviewer(dvi_name)) { + /* Set the WWW browser on it: */ + if (browser) { + char *command = xmalloc(strlen(dvi_name) + + strlen(browser) + 10); + sprintf(command, "%s '%s' &", browser, dvi_name); + if (debug & DBG_HYPER) { + fprintf(stderr, "Executing: %s\n", command); + } + system(command); + free(command); + return 0; + } else { +#if 0 + /* Don't call paint_anchor before window was opened! */ + paint_anchor("Error: WWWBROWSER not set for URL access\n"); +#endif + fprintf(stderr, "You need to set the environment variable WWWBROWSER\n"); + fprintf(stderr, "or specify -browser on the command line to access\n"); + fprintf(stderr, "networked URL's which can't be handled otherwise.\n"); + } + } + } +#endif /* WIN32 */ + else { + if (HTeXnext_extern == 1) { + /* External viewer */ + if (anchor_name != NULL) { + invokedviviewer(dvi_name, anchor_name, 0); + free(anchor_name); + anchor_name = NULL; + } else { + invokedviviewer(dvi_name, NULL, 0); + } + return 0; + } else { + /* Dvi file, ='internal viewer' */ + open_dvi_file(); + if (dvi_file != NULL) { + retitle(dvi_name); + extractbase(dvi_name); + return 1; + } else { + perror(dvi_name); + Exit(1); + } + } + } + return 0; +} + +/* from xhdvi/events.c */ + +/* APS Pointer locator: */ + +int +pointerlocate(xpos, ypos) /* Return screen positions */ +int *xpos, *ypos; +{ + Window root, child; + int root_x, root_y; + unsigned int keys_buttons; + +#ifdef WIN32 + POINT curPos = {0, 0}, ptOrg = {0, 0}; + RECT rcClient, rcClip, rcPage; + BOOL bRet; + extern HWND hWndDraw; + extern int xCurrentScroll, yCurrentScroll; + extern int xMousePos, yMousePos; + + /* Retrieve the page dimensions */ + rcPage.left = 0; + rcPage.top = 0; + rcPage.right = page_w - 1; + rcPage.bottom = page_h - 1; + + if (!GetWindowOrgEx(maneDrawDC, &ptOrg)) { + Win32Error("pointerlocate/GetWindowOrgEx"); + } + + curPos.x = *xpos = xMousePos + xCurrentScroll + ptOrg.x; + curPos.y = *ypos = yMousePos + yCurrentScroll + ptOrg.y; + /* Retrieve the screen coordinates of the client area, + and convert them into client coordinates. */ + GetClientRect(hWndDraw, &rcClient); + /* Intersect both rectangles. The mag. glass will be limited + to the actual visible part of the page. */ + IntersectRect(&rcClip, &rcClient, &rcPage); + bRet = PtInRect(&rcClip, curPos); + return bRet; +#else + return XQueryPointer(DISP, mane.win, &root, &child, + &root_x, &root_y, xpos, ypos, &keys_buttons); +#endif +} + +#endif /* HTEX */ +#endif /* XHDVI || HTEX */ |