/* This is the main file for hacking dvips to do HyperPostScript * Written by Mark D. Doyle 11/94. It is (C) Copyright 1994 by Mark D. Doyle * and the University of California. You may modify and use this program to * your heart's content, so long as you send modifications to Mark Doyle and * abide by the rest of the dvips copyrights. */ #include "dvips.h" #ifdef HPS #include #ifdef KPATHSEA #include #else #define TOLOWER Tolower #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef Tolower #define Tolower tolower #endif #define NAME 0 #define HREF 1 #define skip_space(s) for( ; *s == ' ' ; s++) ; Boolean inHTMLregion = 0 ; Boolean NO_ERROR = 1 ; Boolean HPS_ERROR = 0 ; integer HREF_COUNT ; Boolean ISHREF = 0 ; Boolean POPPED = 0 ; Boolean PUSHED = 0 ; char *current_name ; int current_type ; int current_pushcount ; extern integer pushcount ; #define GoTo 0 #define GoToR 1 #define Launch 2 typedef struct rectangle { double llx ; /* lower left x coor */ double lly ; /* lower left y coor */ double urx ; /* upper right x coor */ double ury ; /* upper right y coor */ } dvipsRectangle ; typedef struct hps_link { int action ; /* GoTo, GoToR, or Launch */ char *file ; /* PDF-style system-independent filename - unused now */ dvipsRectangle rect ; /* rectangle for location of link */ int border[5] ; /* Border info --- with dashes*/ int srcpg ; /* Page of location */ int page ; /* Page of destination --- left out is same as srcpg */ int vert_dest ; /* Vertical position of destination on page */ double color[3] ; /* color: length of array gives colorspace (3 <=> RGB)*/ char *title ; /* Title of link */ } Hps_link ; struct nlist { /* hashtable entry */ struct nlist *next ; /* next entry in chain */ char *name ; /* defined name */ Hps_link *defn ; /* Link associated with name */ } ; typedef struct rect_list { /* linked list of rectangles */ struct rect_list *next ; /* next rectangle in the chain */ dvipsRectangle rect ; } Rect_list ; Rect_list *current_rect_list ; #define HASHSIZE 1223 static struct nlist *link_targets[HASHSIZE] ; /* names .... */ static struct nlist *link_sources[HASHSIZE] ; /* hrefs .... */ #ifdef KPATHSEA #define dup_str xstrdup #else char *dup_str() ; /* duplicate a string */ #endif #include "protos.h" extern Boolean removecomments ; Boolean noprocset ; /* Leave out BeginProc and EndProc comments */ extern int vactualdpi ; extern int pagecounter ; extern integer hhmem, vvmem ; extern integer vpapersize ; /* This was hardcoded to letter size. The denominator converts scaled points to big points (65536*72.27/72). */ #undef PAGESIZE /* HP-UX 10 defines for itself. */ #define PAGESIZE ((int) (vpapersize/65781.76)) #define MARGIN 72 #define VERTICAL 0 #define HORIZONTAL 1 #define FUDGE 2.0 /* For later use * static char *dest_key[9] = {"Fit", "FitB", "FitW", "FitH", "FitBH" "FitR", "FitV", "FitBV", "XYZ"} ; */ extern FILE *bitfile ; extern char *oname ; extern integer pagenum ; extern integer hh ; extern integer vv ; extern integer hoff, voff ; char *hs = NULL ; /* html string to be handled */ char *url_name = NULL ; /* url between double quotes */ /* parse anchor into link */ void do_html P1C(char *, s) { Hps_link *nl ; url_name = (char *)malloc(strlen(s)+1) ; hs = s ; HREF_COUNT = 0 ; skip_space(hs) ; /* skip spaces */ if ( TOLOWER(*hs) == 'a') { /* valid start */ POPPED = FALSE ; if (inHTMLregion) { error("previous html not closed with /A"); return; } else { inHTMLregion = TRUE ; current_rect_list = NULL ; } hs++ ; skip_space(hs) ; while(*hs != '\0') { /* parse for names and href */ if (!href_or_name()) { error("Bad HMTL:") ; error(s) ; error("!") ; break ; } skip_space(hs) ; } } else if ( (*hs == '/') && (TOLOWER(hs[1]) == 'a') ) { if (!inHTMLregion) { error("In html, /A found without previous A") ; return; } else { inHTMLregion = FALSE ; } if (current_type == HREF && current_name[0] != '#') { if ((nl = lookup_link(current_name, current_type)->defn)) { nl->rect.urx = dvi_to_hps_conv(hh + hoff,HORIZONTAL) ; nl->rect.ury = dvi_to_hps_conv(vv + voff, VERTICAL)-FUDGE+12.0 ; stamp_external(current_name,nl); /* Broken lines ? */ } else { error("!Null lookup"); } } else { if ((nl = lookup_link(current_name, current_type)->defn)) { nl->rect.urx = dvi_to_hps_conv(hh + hoff,HORIZONTAL) ; nl->rect.ury = dvi_to_hps_conv(vv + voff, VERTICAL)-FUDGE+12.0 ; if (current_type) { stamp_hps(nl) ; /* Put link info right where special is */ print_rect_list() ; /* print out rectangles */ } } else { error("!Null lookup"); } } } else { error( "No A in html special") ; error(s) ; /*error("!") ;*/ } return ; } int href_or_name P1H(void) { if ((strncmp(hs, "href", 4) == 0) || (strncmp(hs, "HREF", 4) == 0)) { ISHREF = TRUE ; } else if ((strncmp(hs, "name", 4) == 0) || (strncmp(hs, "NAME", 4) == 0)) { ISHREF = FALSE ; } else { error("Not valid href or name html reference") ; return(HPS_ERROR) ; } if(!parseref()) return(HPS_ERROR) ; if (url_name) { if( ISHREF ) { do_link(url_name, HREF) ; } else do_link(url_name, NAME) ; } else { error("No string in qoutes ") ; return(HPS_ERROR) ; } return(NO_ERROR) ; } int parseref P1H(void) { int i = 0 ; for(i=0 ; i++ < 4 ; hs++) ; /* skip href or name in html string */ skip_space(hs) ; if (*hs == '=' ) { hs++ ; } else { error("No equal sign") ; return(HPS_ERROR) ; } if(!get_string()) return(HPS_ERROR) ; return(NO_ERROR) ; /* extract stuff between double quotes */ } int get_string P1H(void) { char *v = url_name ; skip_space(hs) ; /* hash_name() ; */ if (*hs == '"') { for(hs++ ; *hs != '"' && *hs != '\0' ; *v++ = *hs++) ; /* need to esc " */ if(*hs == '"') { hs++ ; *v++ = '\0' ; return(NO_ERROR) ; } else { error("Improper href. Missing closing double quote") ; return(HPS_ERROR) ; } } else { error("Improper href. Missing opening double quote") ; return(HPS_ERROR) ; } } int do_link P2C(char *, s, int, type) { Hps_link *p ; if (HREF_COUNT++ > 0) { error("!HTML string contains more than one href") ; return(HPS_ERROR) ; } p = (Hps_link *)malloc(sizeof(*p)) ; p->action = GoTo ; p->title = (char *)malloc(strlen(s)+1) ; p->title = s ; p->srcpg = pagecounter ; p->rect.llx = dvi_to_hps_conv(hh + hoff,HORIZONTAL) ; p->rect.lly = dvi_to_hps_conv(vv + voff,VERTICAL)-FUDGE ; p->rect.urx = -1.0 ; p->rect.ury = -1.0 ; p->vert_dest = -1 ; p->page = -1 ; p->color[0] = 0 ; p->color[1] = 0 ; /* Blue links */ p->color[2] = 1 ; p->border[0] = 1 ; /* horizontal corner radius */ p->border[1] = 1 ; /* vertical corner radius */ p->border[2] = 1 ; /* box line width */ p->border[3] = 3 ; /* dash on size */ p->border[4] = 3 ; /* dash off size */ current_name = (char *)malloc(strlen(s)+1) ; current_name = s ; current_type = type ; current_pushcount = pushcount ; install_link(s, p, type) ; return(NO_ERROR) ; } unsigned int hash_string P1C(char *, s) { unsigned hashval ; for (hashval = 0 ; *s != '\0' ; s++) hashval = *s + 31 * hashval ; return hashval % HASHSIZE ; } /* lookup a hashed name */ struct nlist *lookup_link P2C(char *, s, int, type) { struct nlist *np ; for(np = type ? link_sources[hash_string(s)] : link_targets[hash_string(s)] ; np != NULL ; np = np -> next) if (strcmp(s, np->name) == 0) return np ; /* found */ return NULL ; /* not found */ } struct nlist *install_link P3C(char *, name, Hps_link *, defn, int, type) { struct nlist *np ; unsigned hashval ; np = (struct nlist *)malloc(sizeof(*np)) ; if (np == NULL || (np->name = dup_str(name)) == NULL) return NULL ; hashval = hash_string(name) ; np->next = type ? link_sources[hashval] : link_targets[hashval] ; (type ? link_sources : link_targets)[hashval] = np ; if ((np->defn = link_dup(defn)) == NULL) return NULL ; return np ; } #ifndef KPATHSEA char *dup_str P1C(char *, w) /* make a duplicate of s */ { char *p ; p = (char *)malloc(strlen(w)+1) ; if (p != NULL) strcpy(p,w) ; return p ; } #endif Hps_link *link_dup P1C(Hps_link *, s) /* make a duplicate link */ { Hps_link *p ; p = (Hps_link *) malloc(sizeof(*p)) ; if (p != NULL) p = s ; return p ; } double dvi_to_hps_conv P2C(int, i, int, dir) { double hps_coor ; /* Convert dvi integers into proper hps coordinates Take into account magnification and resolution that dvi file was produced at */ hps_coor = dir ? (((i * 72.0) / vactualdpi) +MARGIN) : (PAGESIZE - ((i * 72.0) / (vactualdpi)) - MARGIN ) ; return(hps_coor) ; } int vert_loc P1C(int, i) { int return_value ; return_value = (i + (PAGESIZE / 4) + FUDGE) ; if ( return_value > PAGESIZE) { return((int)PAGESIZE) ; } else if (return_value < (PAGESIZE / 4.0)) { return((PAGESIZE / 4)) ; } else return(return_value) ; } Hps_link *dest_link P1C(char *, s) { /* Assume for now that only one entry with same NAME, i.e. Should be true for all legitimate papers. Also, assume prepending of # for names. */ struct nlist *np ; s++ ; /* get rid of hashmark */ for(np = link_targets[hash_string(s)] ; np != NULL ; np = np -> next) { if ( href_name_match(s, np->name)) { return (np->defn) ; /* found */ } } error("Oh no, link not found in target hashtable") ; error(s) ; error("!") ; return NULL ; /* not found */ } int count_targets P1H(void) { int count=0 ; int i ; struct nlist *np ; for (i = 0 ; i < HASHSIZE ; i++) for(np = link_targets[i] ; np != NULL ; np = np -> next) count++ ; return count ; } void do_targets P1H(void) { struct nlist *np ; int i ; Hps_link *dest ; for (i = 0 ; i < HASHSIZE ; i++) for(np = link_sources[i] ; np != NULL ; np = np -> next) { if (np->name[0] == '#') { dest = dest_link(np->name) ; np->defn->page = dest->srcpg ; np->defn->vert_dest = vert_loc((int) dest->rect.lly) ; } } } void do_target_dict P1H(void) { struct nlist *np ; int i ; (void) fprintf(bitfile, "HPSdict begin\n") ; (void)fprintf(bitfile, "/TargetAnchors\n") ; (void)fprintf(bitfile, "%i dict dup begin\n",count_targets()) ; for (i = 0 ; i < HASHSIZE ; i++) for(np = link_targets[i] ; np != NULL ; np = np -> next) (void)fprintf(bitfile, "(%s) [%i [%.0f %.0f %.0f %.0f] %i] def\n", np->defn->title, np->defn->srcpg, np->defn->rect.llx, np->defn->rect.lly, np->defn->rect.urx, np->defn->rect.ury, vert_loc((int) np->defn->rect.lly)) ; (void)fprintf(bitfile,"end targetdump-hook def\n") ; } int href_name_match P2C(char *, h, char *, n) { int count = 0 ; int name_length = strlen(n) ; while((*h == *n) & (*h != '\0') ) { count++ ; h++ ; n++ ; } if (name_length == count) { return 1 ; } else { /* printf(" count: %i \n", count) ; */ return 0 ; } } void stamp_hps P1C(Hps_link *, pl) { char tmpbuf[200] ; if (pl == NULL) { error("Null pointer, oh no!") ; return ; } else { /* print out the proper pdfm with local page info only * target info will be in the target dictionary */ (void)sprintf(tmpbuf, " (%s) [[%.0f %.0f %.0f %.0f] [%i %i %i [%i %i]] [%.0f %.0f %.0f]] pdfm ", pl->title, pl->rect.llx, pl->rect.lly, pl->rect.urx, pl->rect.ury, pl->border[0], pl->border[1], pl->border[2], pl->border[3],pl->border[4], pl->color[0], pl->color[1], pl->color[2]) ; cmdout(tmpbuf) ; } } /* For external URL's, we just pass them through as a string. The hyperps * interpreter can then do what is wants with them. */ void stamp_external P2C(char *, s, Hps_link *, pl) { char tmpbuf[200]; if (pl == NULL) { error("Null pointer, oh no!") ; return ; } else { /* print out the proper pdfm with local page info only * target info will be in the target dictionary */ (void)sprintf(tmpbuf," [[%.0f %.0f %.0f %.0f] [%i %i %i [%i %i]] [%.0f %.0f %.0f]] (%s) pdfm ", pl->rect.llx, pl->rect.lly, pl->rect.urx, pl->rect.ury, pl->border[0], pl->border[1], pl->border[2], pl->border[3],pl->border[4], pl->color[0], pl->color[1], pl->color[2], s) ; cmdout(tmpbuf) ; } } void finish_hps P1H(void) { fclose(bitfile) ; set_bitfile("head.tmp",1); do_targets() ; do_target_dict(); (void)fprintf(bitfile, "TeXDict begin\n") ; (void)fprintf(bitfile, "%%%%EndSetup\n") ; fclose(bitfile) ; open_output() ; noprocset = 1 ; removecomments = 0; copyfile("head.tmp") ; copyfile("body.tmp") ; } void set_bitfile P2C(char *, s, int, mode) { if ((bitfile=fopen(s, mode ? FOPEN_ABIN_MODE : FOPEN_WBIN_MODE))==NULL) { error(s) ; error("!couldn't open file") ; } } void vertical_in_hps P1H(void) { Rect_list *rl ; /*printf("in vertical_in_hps") ; */ if (current_type == NAME) return; /* Handle this case later */ if (!current_rect_list) { current_rect_list = (Rect_list *)malloc(sizeof(Rect_list)) ; current_rect_list->next = NULL ; } else { rl = (Rect_list *)malloc(sizeof(Rect_list)) ; rl->next = current_rect_list ; current_rect_list = rl ; } current_rect_list->rect.llx = dvi_to_hps_conv(hh + hoff,HORIZONTAL) ; current_rect_list->rect.lly = dvi_to_hps_conv(vv + voff,VERTICAL)-FUDGE ; current_rect_list->rect.urx = dvi_to_hps_conv(hhmem, HORIZONTAL) ; current_rect_list->rect.ury = dvi_to_hps_conv(vvmem, VERTICAL)-FUDGE ; if (POPPED) start_new_box() ; } void print_rect_list P1H(void) { Rect_list *rl ; for(rl = current_rect_list ; rl != NULL ; rl = rl -> next) { /* printf("Rectangle is %.0f, %.0f, %.0f, %.0f\n", rl->rect.llx, rl->rect.lly, rl->rect.urx, rl->rect.ury) ; */ free(rl) ; } } void end_current_box P1H(void) { Hps_link *nl ; POPPED = TRUE ; HREF_COUNT-- ; if (current_type == HREF && current_name[0] != '#') { if ((nl = lookup_link(current_name, current_type)->defn)) { nl->rect.urx = dvi_to_hps_conv(hhmem + hoff,HORIZONTAL) ; nl->rect.ury = dvi_to_hps_conv(vvmem + voff, VERTICAL)-FUDGE+12.0 ; stamp_external(current_name,nl); /* Broken lines ? */ } else { error("!Null lookup"); } } else { if ((nl = lookup_link(current_name, current_type)->defn)) { nl->rect.urx = dvi_to_hps_conv(hhmem + hoff,HORIZONTAL) ; nl->rect.ury = dvi_to_hps_conv(vvmem + voff, VERTICAL)-FUDGE+12.0 ; if (current_type) { stamp_hps(nl) ; /* Put link info right where special is */ } } else { error("!Null lookup"); } /* printf("Ended box %.0f, %.0f, %.0f, %.0f\n", nl->rect.llx, \ nl->rect.lly,nl->rect.urx, nl->rect.ury) ; */ } } void start_new_box P1H(void) { POPPED = FALSE ; do_link(current_name, current_type) ; } #else int no_hypertex ; /* prevent an empty file */ #endif