/*************************************************************************/ /* Copyright (c) 2004 */ /* Daniel Sleator, David Temperley, and John Lafferty */ /* All rights reserved */ /* */ /* Use of the link grammar parsing system is subject to the terms of the */ /* license set forth in the LICENSE file included with this software, */ /* and also available at http://www.link.cs.cmu.edu/link/license.html */ /* This license allows free redistribution and use in source and binary */ /* forms, with or without modification, subject to certain conditions. */ /* */ /*************************************************************************/ #include #include #include "corpus/corpus.h" const char * trailer(int mode); const char * header(int mode); static void set_centers(Linkage linkage, int center[], int print_word_0, int N_words_to_print) { mbstate_t mbss; int i, len, tot; memset(&mbss, 0, sizeof(mbss)); tot = 0; if (print_word_0) i=0; else i=1; for (; i < N_words_to_print; i++) { /* Centers obtained by counting the characters, * not the bytes in the string. * len = strlen(linkage->word[i]); */ len = mbsrtowcs(NULL, &linkage->word[i], 0, &mbss); center[i] = tot + (len/2); tot += len+1; } } /* the following are all for generating postscript */ typedef struct { int N_rows; /* N_rows -- the number of rows */ /* tells the height of the links above the sentence */ int link_heights[MAX_LINKS]; /* the word beginning each row of the display */ int row_starts[MAX_SENTENCE]; } ps_ctxt_t; /** * prints s then prints the last |t|-|s| characters of t. * if s is longer than t, it truncates s. */ static void left_append_string(String * string, const char * s, const char * t) { int i, j, k; j = strlen(t); k = strlen(s); for (i=0; idict; int l, r; const char *label, *llabel, *rlabel; l = linkage_get_link_lword(linkage, link); r = linkage_get_link_rword(linkage, link); label = linkage_get_link_label(linkage, link); llabel = linkage_get_link_llabel(linkage, link); rlabel = linkage_get_link_rlabel(linkage, link); if ((l == 0) && dict->left_wall_defined) { left_append_string(s, LEFT_WALL_DISPLAY," "); } else if ((l == (linkage_get_num_words(linkage)-1)) && dict->right_wall_defined) { left_append_string(s, RIGHT_WALL_DISPLAY," "); } else { left_append_string(s, linkage_get_word(linkage, l), " "); } left_append_string(s, llabel, " "); append_string(s, " <---"); left_append_string(s, label, "-----"); append_string(s, "-> "); left_append_string(s, rlabel, " "); append_string(s, " %s\n", linkage_get_word(linkage, r)); } /** * To the left of each link, print the sequence of domains it is in. * Printing a domain means printing its type. * Takes info from pp_link_array and pp and chosen_words. */ char * linkage_print_links_and_domains(Linkage linkage) { int link, longest, j; int N_links = linkage_get_num_links(linkage); String * s = string_new(); char * links_string; const char ** dname; longest = 0; for (link=0; link longest) longest = linkage_get_link_num_domains(linkage, link); } for (link=0; linksent; int nwords = sent->length; /* Decrement nwords, so as to ignore the RIGHT-WALL */ nwords --; /* Loop over each word in the sentence (skipping LEFT-WALL, which is * word 0. */ for (w=1; wword[w].d is NULL */ if (sent->word[w].d) infword = sent->word[w].d->string; else infword = sent->word[w].string; dj = linkage_get_disjunct(linkage, w); append_string(s, "%21s %s\n", infword, dj); } djs = string_copy(s); string_delete(s); return djs; } /** */ static char * build_linkage_postscript_string(Linkage linkage, ps_ctxt_t *pctx) { int link, i,j; int d; int print_word_0 = 0, print_word_N = 0, N_wall_connectors, suppressor_used; Sublinkage *sublinkage = &(linkage->sublinkage[linkage->current]); int N_links = sublinkage->num_links; Link **ppla = sublinkage->link; String * string; char * ps_string; Dictionary dict = linkage->sent->dict; Parse_Options opts = linkage->opts; int N_words_to_print; string = string_new(); N_wall_connectors = 0; if (dict->left_wall_defined) { suppressor_used = FALSE; if (!opts->display_walls) for (j=0; jl == 0) { if (ppla[j]->r == linkage->num_words-1) continue; N_wall_connectors ++; if (strcmp(ppla[j]->lc->string, LEFT_WALL_SUPPRESS)==0) { suppressor_used = TRUE; } } } print_word_0 = (((!suppressor_used) && (N_wall_connectors != 0)) || (N_wall_connectors > 1) || opts->display_walls); } else { print_word_0 = TRUE; } N_wall_connectors = 0; if (dict->right_wall_defined) { suppressor_used = FALSE; for (j=0; jr == linkage->num_words-1) { N_wall_connectors ++; if (strcmp(ppla[j]->lc->string, RIGHT_WALL_SUPPRESS)==0){ suppressor_used = TRUE; } } } print_word_N = (((!suppressor_used) && (N_wall_connectors != 0)) || (N_wall_connectors > 1) || opts->display_walls); } else { print_word_N = TRUE; } if (print_word_0) d=0; else d=1; i = 0; N_words_to_print = linkage->num_words; if (!print_word_N) N_words_to_print--; append_string(string, "["); for (j=d; j0)) append_string(string, "\n"); i++; append_string(string, "(%s)", linkage->word[j]); } append_string(string,"]"); append_string(string,"\n"); append_string(string,"["); j = 0; for (link=0; linkl == 0)) continue; if (!print_word_N && (ppla[link]->r == linkage->num_words-1)) continue; if (ppla[link]->l == -1) continue; if ((j%7 == 0) && (j>0)) append_string(string,"\n"); j++; append_string(string,"[%d %d %d", ppla[link]->l-d, ppla[link]->r-d, pctx->link_heights[link]); if (ppla[link]->lc->label < 0) { append_string(string," (%s)]", ppla[link]->name); } else { append_string(string," ()]"); } } append_string(string,"]"); append_string(string,"\n"); append_string(string,"["); for (j=0; j < pctx->N_rows; j++ ) { if (j>0) append_string(string, " %d", pctx->row_starts[j]); else append_string(string,"%d", pctx->row_starts[j]); } append_string(string,"]\n"); ps_string = string_copy(string); string_delete(string); return ps_string; } /** * This takes the current chosen_disjuncts array and uses it to * compute the chosen_words array. "I.xx" suffixes are eliminated. */ void compute_chosen_words(Sentence sent, Linkage linkage) { int i, l; const char *t; char * s, *u; Parse_info pi = sent->parse_info; const char * chosen_words[MAX_SENTENCE]; Parse_Options opts = linkage->opts; for (i=0; ilength; i++) { /* get rid of those ugly ".Ixx" */ chosen_words[i] = sent->word[i].string; if (pi->chosen_disjuncts[i] == NULL) { /* no disjunct is used on this word because of null-links */ t = chosen_words[i]; l = strlen(t) + 2; s = (char *) xalloc(l+1); sprintf(s, "[%s]", t); t = string_set_add(s, sent->string_set); xfree(s, l+1); chosen_words[i] = t; } else if (opts->display_word_subscripts) { t = pi->chosen_disjuncts[i]->string; if (is_idiom_word(t)) { l = strlen(t); s = (char *) xalloc(l+1); strcpy(s,t); for (u=s; *u != '.'; u++) ; *u = '\0'; t = string_set_add(s, sent->string_set); xfree(s, l+1); chosen_words[i] = t; } else { chosen_words[i] = t; } } } if (sent->dict->left_wall_defined) { chosen_words[0] = LEFT_WALL_DISPLAY; } if (sent->dict->right_wall_defined) { chosen_words[sent->length-1] = RIGHT_WALL_DISPLAY; } for (i=0; inum_words; ++i) { s = (char *) exalloc(strlen(chosen_words[i])+1); strcpy(s, chosen_words[i]); linkage->word[i] = s; } } #define MAX_HEIGHT 30 /** * String allocated with exalloc. * Needs to be freed with linkage_free_diagram() */ static char * linkage_print_diagram_ctxt(Linkage linkage, ps_ctxt_t *pctx) { int i, j, k, cl, cr, row, top_row, width, flag; const char *s; char *t; int print_word_0 = 0, print_word_N = 0, N_wall_connectors, suppressor_used; int center[MAX_SENTENCE]; char connector[MAX_TOKEN_LENGTH]; int line_len, link_length; Sublinkage *sublinkage=&(linkage->sublinkage[linkage->current]); int N_links = sublinkage->num_links; Link **ppla = sublinkage->link; String * string; char * gr_string; Dictionary dict = linkage->sent->dict; Parse_Options opts = linkage->opts; int x_screen_width = parse_options_get_screen_width(opts); int N_words_to_print; char picture[MAX_HEIGHT][MAX_LINE]; char xpicture[MAX_HEIGHT][MAX_LINE]; string = string_new(); N_wall_connectors = 0; if (dict->left_wall_defined) { suppressor_used = FALSE; if (!opts->display_walls) { for (j=0; jl == 0)) { if (ppla[j]->r == linkage->num_words-1) continue; N_wall_connectors ++; if (strcmp(ppla[j]->lc->string, LEFT_WALL_SUPPRESS)==0) { suppressor_used = TRUE; } } } } print_word_0 = (((!suppressor_used) && (N_wall_connectors != 0)) || (N_wall_connectors > 1) || opts->display_walls); } else { print_word_0 = TRUE; } N_wall_connectors = 0; if (dict->right_wall_defined) { suppressor_used = FALSE; for (j=0; jr == linkage->num_words-1) { N_wall_connectors ++; if (strcmp(ppla[j]->lc->string, RIGHT_WALL_SUPPRESS)==0) { suppressor_used = TRUE; } } } print_word_N = (((!suppressor_used) && (N_wall_connectors != 0)) || (N_wall_connectors > 1) || opts->display_walls); } else { print_word_N = TRUE; } N_words_to_print = linkage->num_words; if (!print_word_N) N_words_to_print--; set_centers(linkage, center, print_word_0, N_words_to_print); line_len = center[N_words_to_print-1]+1; for (k=0; kl == -1) continue; if ((ppla[j]->r - ppla[j]->l) != link_length) continue; if (!print_word_0 && (ppla[j]->l == 0)) continue; /* gets rid of the irrelevant link to the left wall */ if (!print_word_N && (ppla[j]->r == linkage->num_words-1)) continue; /* gets rid of the irrelevant link to the right wall */ /* put it into the lowest position */ cl = center[ppla[j]->l]; cr = center[ppla[j]->r]; for (row=0; row < MAX_HEIGHT; row++) { for (k=cl+1; klink_heights[j] = row; if (2*row+2 > MAX_HEIGHT-1) { append_string(string, "The diagram is too high.\n"); gr_string = string_copy(string); string_delete(string); return gr_string; } if (row > top_row) top_row = row; picture[row][cl] = '+'; picture[row][cr] = '+'; for (k=cl+1; kname; if (opts->display_link_subscripts) { if (!is_utf8_alpha(s)) s = ""; } else { if (!is_utf8_upper(s)) { s = ""; /* Don't print fat link connector name */ } } strncpy(connector, s, MAX_TOKEN_LENGTH-1); connector[MAX_TOKEN_LENGTH-1] = '\0'; k=0; if (opts->display_link_subscripts) k = strlen(connector); else for (t=connector; isupper((int)*t); t++) k++; /* uppercase len of conn*/ if ((cl+cr-k)/2 + 1 <= cl) { t = picture[row] + cl + 1; } else { t = picture[row] + (cl+cr-k)/2 + 1; } s = connector; if (opts->display_link_subscripts) while((*s != '\0') && (*t == '-')) *t++ = *s++; else while(isupper((int)*s) && (*t == '-')) *t++ = *s++; /* now put in the | below this one, where needed */ for (k=0; kword[k]; i=0; while(*s != '\0') { *t++ = *s++; i++; } *t++ = ' '; } *t = '\0'; if (opts->display_short) { for (k=0; picture[0][k] != '\0'; k++) { if ((picture[0][k] == '+') || (picture[0][k] == '|')) { xpicture[1][k] = '|'; } else { xpicture[1][k] = ' '; } } xpicture[1][k] = '\0'; for (row=0; row < top_row+1; row++) { strcpy(xpicture[row+2],picture[row]); } top_row = top_row+2; } else { for (row=0; row < top_row+1; row++) { strcpy(xpicture[2*row+2],picture[row]); for (k=0; picture[row][k] != '\0'; k++) { if ((picture[row][k] == '+') || (picture[row][k] == '|')) { xpicture[2*row+1][k] = '|'; } else { xpicture[2*row+1][k] = ' '; } } xpicture[2*row+1][k] = '\0'; } top_row = 2*top_row + 2; } /* we've built the picture, now print it out */ if (print_word_0) i = 0; else i = 1; k = 0; pctx->N_rows = 0; pctx->row_starts[pctx->N_rows] = 0; pctx->N_rows++; while(i < N_words_to_print) { append_string(string, "\n"); width = 0; do { width += strlen(linkage->word[i])+1; i++; } while((iword[i]))+1 < x_screen_width)); pctx->row_starts[pctx->N_rows] = i - (!print_word_0); /* PS junk */ if (iN_rows++; /* same */ for (row = top_row; row >= 0; row--) { flag = TRUE; for (j=k;flag&&(jlength; i++) { c = 0; for (d=sent->word[i].d; d != NULL; d = d->next) { c++; } printf("%s(%d) ",sent->word[i].string, c); } printf("\n\n"); } void print_expression_sizes(Sentence sent) { X_node * x; int w, size; for (w=0; wlength; w++) { size = 0; for (x=sent->word[w].x; x!=NULL; x = x->next) { size += size_of_expression(x->exp); } printf("%s[%d] ",sent->word[w].string, size); } printf("\n\n"); } /** * this version just prints it on one line. */ void print_sentence(FILE *fp, Sentence sent, int w) { int i; if (sent->dict->left_wall_defined) i=1; else i=0; for (; ilength - sent->dict->right_wall_defined; i++) { fprintf(fp, "%s ", sent->word[i].string); } fprintf(fp, "\n"); } const char * trailer(int mode) { static const char * trailer_string= "diagram\n" "\n" "%%EndDocument\n" ; if (mode==1) return trailer_string; else return ""; } const char * header(int mode) { static const char * header_string= "%!PS-Adobe-2.0 EPSF-1.2\n" "%%Pages: 1\n" "%%BoundingBox: 0 -20 500 200\n" "%%EndComments\n" "%%BeginDocument: \n" "\n" "% compute size of diagram by adding\n" "% #rows x 8.5\n" "% (#rows -1) x 10\n" "% \\sum maxheight x 10\n" "/nulllink () def % The symbol of a null link\n" "/wordfontsize 11 def % the size of the word font\n" "/labelfontsize 9 def % the size of the connector label font\n" "/ex 10 def % the horizontal radius of all the links\n" "/ey 10 def % the height of the level 0 links\n" "/ed 10 def % amount to add to this height per level\n" "/radius 10 def % radius for rounded arcs\n" "/row-spacing 10 def % the space between successive rows of the diagram\n" "\n" "/gap wordfontsize .5 mul def % the gap between words\n" "/top-of-words wordfontsize .85 mul def\n" " % the delta y above where the text is written where\n" " % the major axis of the ellipse is located\n" "/label-gap labelfontsize .1 mul def\n" "\n" "/xwordfontsize 10 def % the size of the word font\n" "/xlabelfontsize 10 def % the size of the connector label font\n" "/xex 10 def % the horizontal radius of all the links\n" "/xey 10 def % the height of the level 0 links\n" "/xed 10 def % amount to add to this height per level\n" "/xradius 10 def % radius for rounded arcs\n" "/xrow-spacing 10 def % the space between successive rows of the diagram\n" "/xgap wordfontsize .5 mul def % the gap between words\n" "\n" "/centerpage 6.5 72 mul 2 div def\n" " % this number of points from the left margin is the center of page\n" "\n" "/rightpage 6.5 72 mul def\n" " % number of points from the left margin is the the right margin\n" "\n" "/show-string-centered-dict 5 dict def\n" "\n" "/show-string-centered {\n" " show-string-centered-dict begin\n" " /string exch def\n" " /ycenter exch def\n" " /xcenter exch def\n" " xcenter string stringwidth pop 2 div sub\n" " ycenter labelfontsize .3 mul sub\n" " moveto\n" " string show\n" " end\n" "} def\n" "\n" "/clear-word-box {\n" " show-string-centered-dict begin\n" " /string exch def\n" " /ycenter exch def\n" " /xcenter exch def\n" " newpath\n" " /urx string stringwidth pop 2 div def\n" " /ury labelfontsize .3 mul def\n" " xcenter urx sub ycenter ury sub moveto\n" " xcenter urx add ycenter ury sub lineto\n" " xcenter urx add ycenter ury add lineto\n" " xcenter urx sub ycenter ury add lineto\n" " closepath\n" " 1 setgray fill\n" " 0 setgray\n" " end\n" "} def\n" "\n" "/diagram-sentence-dict 20 dict def\n" "\n" "/diagram-sentence-circle\n" "{diagram-sentence-dict begin \n" " /links exch def\n" " /words exch def\n" " /n words length def\n" " /Times-Roman findfont wordfontsize scalefont setfont\n" " /x 0 def\n" " /y 0 def\n" "\n" " /left-ends [x dup words {stringwidth pop add gap add dup}\n" " forall pop pop] def\n" " /right-ends [x words {stringwidth pop add dup gap add} forall pop] def\n" " /centers [0 1 n 1 sub {/i exch def\n" " left-ends i get\n" " right-ends i get\n" " add 2 div\n" " } for ] def\n" "\n" " x y moveto\n" " words {show gap 0 rmoveto} forall\n" "\n" " .5 setlinewidth \n" "\n" " links {dup 0 get /leftword exch def\n" " dup 1 get /rightword exch def\n" " dup 2 get /level exch def\n" " 3 get /string exch def\n" " newpath\n" " string nulllink eq {[2] 1 setdash}{[] 0 setdash} ifelse\n" "% string nulllink eq {.8 setgray}{0 setgray} ifelse\n" " centers leftword get\n" " y top-of-words add\n" " moveto\n" " \n" " centers rightword get\n" " centers leftword get\n" " sub 2 div dup\n" " radius \n" " lt {/radiusx exch def}{pop /radiusx radius def} ifelse\n" " \n" " \n" " \n" " centers leftword get\n" " y top-of-words add ey ed level mul add add\n" " centers rightword get\n" " y top-of-words add ey ed level mul add add\n" " radiusx\n" " arcto\n" " 4 {pop} repeat\n" " centers rightword get\n" " y top-of-words add ey ed level mul add add\n" " centers rightword get\n" " y top-of-words add\n" " radiusx\n" " arcto\n" " 4 {pop} repeat\n" " centers rightword get\n" " y top-of-words add\n" " lineto\n" "\n" " stroke\n" "\n" " /radius-y ey ed level mul add def\n" "\n" " /center-arc-x\n" " centers leftword get centers rightword get add 2 div\n" " def\n" " \n" " /center-arc-y\n" " y top-of-words radius-y add add\n" " def\n" "\n" " /Courier-Bold findfont labelfontsize scalefont setfont \n" " center-arc-x center-arc-y string clear-word-box\n" " center-arc-x center-arc-y string show-string-centered\n" " } forall\n" " end\n" " } def\n" "\n" "/diagramdict 20 dict def\n" "\n" "/diagram\n" "{diagramdict begin\n" " /break-words exch def\n" " /links exch def\n" " /words exch def\n" " /n words length def\n" " /n-rows break-words length def\n" " /Times-Roman findfont wordfontsize scalefont setfont\n" "\n" " /left-ends [0 dup words {stringwidth pop add gap add dup}\n" " forall pop pop] def\n" " /right-ends [0 words {stringwidth pop add dup gap add} forall pop] def\n" "\n" " /lwindows [ break-words {left-ends exch get gap 2 div sub } forall ] def\n" " /rwindows [1 1 n-rows 1 sub {/i exch def\n" " lwindows i get } for\n" " right-ends n 1 sub get gap 2 div add\n" " ] def\n" "\n" "\n" " /max 0 def\n" " 0 1 links length 1 sub {\n" " /i exch def\n" " /t links i get 2 get def\n" " t max gt {/max t def} if\n" " } for\n" "\n" " /max-height ed max mul ey add top-of-words add row-spacing add def\n" " /total-height n-rows max-height mul row-spacing sub def\n" "\n" " /max-width 0 def % compute the widest window\n" " 0 1 n-rows 1 sub {\n" " /i exch def\n" " /t rwindows i get lwindows i get sub def\n" " t max-width gt {/max-width t def} if\n" " } for\n" "\n" " centerpage max-width 2 div sub 0 translate % centers it\n" " % rightpage max-width sub 0 translate % right justified\n" " % Delete both of these to make it left justified\n" "\n" " n-rows 1 sub -1 0\n" " {/i exch def\n" " gsave\n" " newpath\n" " %/centering centerpage rwindows i get lwindows i get sub 2 div sub def\n" " % this line causes each row to be centered\n" " /centering 0 def\n" " % set centering to 0 to prevent centering of each row \n" "\n" " centering -100 moveto % -100 because some letters go below zero\n" " centering max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " -100 lineto\n" " closepath\n" " clip\n" " lwindows i get neg n-rows i sub 1 sub max-height mul translate\n" " centerpage centering 0 translate\n" " words links diagram-sentence-circle\n" " grestore\n" " } for\n" " end\n" "} def \n" "\n" "/diagramx\n" "{diagramdict begin\n" " /break-words exch def\n" " /links exch def\n" " /words exch def\n" " /n words length def\n" " /n-rows break-words length def\n" " /Times-Roman findfont xwordfontsize scalefont setfont\n" "\n" " /left-ends [0 dup words {stringwidth pop add gap add dup}\n" " forall pop pop] def\n" " /right-ends [0 words {stringwidth pop add dup gap add} forall pop] def\n" "\n" " /lwindows [ break-words {left-ends exch get gap 2 div sub } forall ] def\n" " /rwindows [1 1 n-rows 1 sub {/i exch def\n" " lwindows i get } for\n" " right-ends n 1 sub get xgap 2 div add\n" " ] def\n" "\n" "\n" " /max 0 def\n" " 0 1 links length 1 sub {\n" " /i exch def\n" " /t links i get 2 get def\n" " t max gt {/max t def} if\n" " } for\n" "\n" " /max-height xed max mul xey add top-of-words add xrow-spacing add def\n" " /total-height n-rows max-height mul xrow-spacing sub def\n" "\n" " /max-width 0 def % compute the widest window\n" " 0 1 n-rows 1 sub {\n" " /i exch def\n" " /t rwindows i get lwindows i get sub def\n" " t max-width gt {/max-width t def} if\n" " } for\n" "\n" " centerpage max-width 2 div sub 0 translate % centers it\n" " % rightpage max-width sub 0 translate % right justified\n" " % Delete both of these to make it left justified\n" "\n" " n-rows 1 sub -1 0\n" " {/i exch def\n" " gsave\n" " newpath\n" " %/centering centerpage rwindows i get lwindows i get sub 2 div sub def\n" " % this line causes each row to be centered\n" " /centering 0 def\n" " % set centering to 0 to prevent centering of each row \n" "\n" " centering -100 moveto % -100 because some letters go below zero\n" " centering max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " -100 lineto\n" " closepath\n" " clip\n" " lwindows i get neg n-rows i sub 1 sub max-height mul translate\n" " centerpage centering 0 translate\n" " words links diagram-sentence-circle\n" " grestore\n" " } for\n" " end\n" "} def \n" "\n" "/ldiagram\n" "{diagramdict begin\n" " /break-words exch def\n" " /links exch def\n" " /words exch def\n" " /n words length def\n" " /n-rows break-words length def\n" " /Times-Roman findfont wordfontsize scalefont setfont\n" "\n" " /left-ends [0 dup words {stringwidth pop add gap add dup}\n" " forall pop pop] def\n" " /right-ends [0 words {stringwidth pop add dup gap add} forall pop] def\n" "\n" " /lwindows [ break-words {left-ends exch get gap 2 div sub } forall ] def\n" " /rwindows [1 1 n-rows 1 sub {/i exch def\n" " lwindows i get } for\n" " right-ends n 1 sub get gap 2 div add\n" " ] def\n" "\n" "\n" " /max 0 def\n" " 0 1 links length 1 sub {\n" " /i exch def\n" " /t links i get 2 get def\n" " t max gt {/max t def} if\n" " } for\n" "\n" " /max-height ed max mul ey add top-of-words add row-spacing add def\n" " /total-height n-rows max-height mul row-spacing sub def\n" "\n" " /max-width 0 def % compute the widest window\n" " 0 1 n-rows 1 sub {\n" " /i exch def\n" " /t rwindows i get lwindows i get sub def\n" " t max-width gt {/max-width t def} if\n" " } for\n" "\n" " % centerpage max-width 2 div sub 0 translate % centers it\n" " % rightpage max-width sub 0 translate % right justified\n" " % Delete both of these to make it left justified\n" "\n" " n-rows 1 sub -1 0\n" " {/i exch def\n" " gsave\n" " newpath\n" " %/centering centerpage rwindows i get lwindows i get sub 2 div sub def\n" " % this line causes each row to be centered\n" " /centering 0 def\n" " % set centering to 0 to prevent centering of each row \n" "\n" " centering -100 moveto % -100 because some letters go below zero\n" " centering max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " max-height n-rows mul lineto\n" " rwindows i get lwindows i get sub centering add\n" " -100 lineto\n" " closepath\n" " clip\n" " lwindows i get neg n-rows i sub 1 sub max-height mul translate\n" " centerpage centering 0 translate\n" " words links diagram-sentence-circle\n" " grestore\n" " } for\n" " end\n" "} def \n" ; if (mode==1) return header_string; else return ""; }