/*****************************************************************************/ /* */ /* Unit: LATPOST (Local Alignments to Text - PostScript output generation) */ /* */ /* Author: Nikola Stojanovic */ /* */ /* Revision: 15 MAY 93 Version 2.0 */ /* 31 JUL 93 Version 2.1 */ /* 27 DEC 93 Version 2.2 */ /* */ /* Unit contains code for generation of PostScript output based on alignment */ /* information stored in the received structures */ /* */ /*****************************************************************************/ #include #include #include #include "alib.h" #include "latsyst.h" /*****************************************************************************/ /* */ /* Unit "global" variables - module level */ /* */ /*****************************************************************************/ int dump_number; /* Current number of PostScript file to generate */ FILE *ps_file; /* File pointer for PostScript output */ int left_x; /* X coordinate of the left margin of the page */ int top_y; /* Y coordinate of the top margin of the page */ int page_position; /* Portrait or landscape layout */ int down_skip; /* Interline vertical distance for implementing "newline" */ int text_font; /* Maximal size of Courier font to be used for sequences text */ int front_size; /* Size of the "front end", containing banner information */ int page_lines; /* Number of text lines on the page */ int margin; /* Number of sequence text characters per line */ bool first_tickmarks; /* Is the first line in the blocks tickmark line? */ bool count_added; /* Are the tickmarks accompanied by count information? */ int position; /* Current buffer position for the output */ ibox_ptr current_box; /* Start of the remainder of the box list for drawing */ iunder_ptr current_underline; /* ... and the same for underlines */ pos_ptr position_lines; /* List of position-line relations */ bool label_set; /* Indicator whether the label was set for current box */ double thickness; /* Line thickness for drawing boxes, underlines ... */ int pages; /* Number of pages created so far ... (total at the end) */ /*****************************************************************************/ /* */ /* Unit local procedures - not callable from outside (forward declarations) */ /* */ /*****************************************************************************/ int POST_MaxFont_Front (instance_ptr template); int POST_MaxFont_Line (instance_ptr template); int POST_MaxFont_Trail (instance_ptr template); int POST_Print_Header (char *description, int max_line); void POST_Set_Variables (int margin, int max_front, int max_line); void POST_All (int used, instance_ptr template, int dim, long int size, Buffer_Vector *buffers); void POST_Put_Block (int used, int vertical, instance_ptr template, int dim, long int size, Buffer_Vector *buffers); void POST_Conclude_Page (Buffer_Vector *buffers, long int size); void POST_Boxes (Buffer_Vector *buffers, long int size); void POST_Underlines (Buffer_Vector *buffers, long int size); void POST_Place_Single_Box (ibox_ptr box, Buffer_Vector *buffers, long int size); void POST_Draw_Box0 (long int from, long int to, int line, int height, char *style); void POST_Draw_Box1 (long int from, long int to, int line, int height, char *style); void POST_Draw_Box2 (long int from, long int to, int line, int height, char *style); void POST_Draw_Box3 (long int from, long int to, int line, int height, char *style); void POST_Draw_Label (ibox_ptr box, int height, Buffer_Vector *buffers, long int size); void POST_Set_Point (int line, int offset); void POST_Place_Single_Underline (iunder_ptr underline, Buffer_Vector *buffers, long int size); void POST_Draw_Underline (long int from, long int to, int line, int kind, char *style); int POST_Underlined_Sequence (iunder_ptr rec, long int from, long int to, Buffer_Vector *buffers, long int size); void POST_Label_Underline (iunder_ptr underline, int height, Buffer_Vector *buffers, long int size); void POST_Set_String_Width (label_ptr label); void POST_Assemble_Label (label_ptr label); /*****************************************************************************/ /* */ /* Interface procedures of the POST(Script) display module */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Procedure: POST_Initialize */ /* */ /* Initialization of module internal data structures */ void POST_Initialize (void) { dump_number = 0; } /*****************************************************************************/ /* */ /* Procedure: POST_Show */ /* */ /* Procedure to generate the PostScript file with formatted output with */ /* respect to the current alignment and received template instance */ void POST_Show (int direction, char *description, instance_ptr template, int dim, long int size, Buffer_Vector *buffers) { char file_name [FNAME_SIZE]; bool banner_set; int page_pixels, max_front, max_line, max_trail, max_font, index, used_lines; /* Create a new PostScript file name, open it and write the header */ if (direction == FILE_OUT) { sprintf (file_name, "lat%d.ps", dump_number); dump_number++; ps_file = fopen (file_name, "w"); } else ps_file = stdout; fprintf (ps_file, "%%!PS-Adobe-1.0\n"); fprintf (ps_file, "%%%%Creator: lat\n"); fprintf (ps_file, "%%%%Pages: (atend)\n"); fprintf (ps_file, "%%%%EndComments\n\n"); /* Determine first whether page position should be "portait" or "landscape" */ if (template -> page == LANDSCAPE) { left_x = PSX_TOPLEFT; top_y = PSY_TOPLEFT_LANDSCAPE; if (template -> page_size == 0) page_pixels = DEFAULT_LANDSCAPE_SIZE; else page_pixels = template -> page_size; } else { left_x = PSX_TOPLEFT; top_y = PSY_TOPLEFT_PORTRAIT; if (template -> page_size == 0) page_pixels = DEFAULT_PORTRAIT_SIZE; else page_pixels = template -> page_size; } page_position = template -> page; /* Determine some general parameters of this PostScript output (this file) */ max_front = POST_MaxFont_Front (template); /* Maximal font size for banners */ max_line = POST_MaxFont_Line (template); /* Max. font size for text lines */ max_trail = POST_MaxFont_Trail (template); /* Max. font size for trailers */ text_font = max_line; if (max_front > max_line) { if (max_front > max_trail) max_font = max_front; else max_font = max_trail; } else if (max_line > max_trail) max_font = max_line; else max_font = max_trail; down_skip = max_font; /* Number of PS pixels to skip from line to line */ banner_set = FALSE; for (index = 0; index < dim; index++) if ((buffers [index]).banner) banner_set = TRUE; if (banner_set) front_size = 9; else front_size = 0; /* Num. banner chars. */ page_lines = (int) (page_pixels / max_font); /* Number of lines per page */ margin = template -> margins; /* Copy the number of sequence chars per line */ if ((template -> top) -> code > 0) { /* Tickmarks at top one */ first_tickmarks = TRUE; if (template -> origins != NULL) count_added = TRUE; /* Count as well */ else count_added = FALSE; } else { first_tickmarks = count_added = FALSE; } /* No tickmarks at the top */ pages = 0; /* Initialize the number of pages (0 so far) */ if (page_lines < dim) { CONT_Error ("Page requested too small for the alignment"); } else { /* Set all sizes that depend on Postscript fonts as PostScript variables */ POST_Set_Variables (template -> margins, max_front, max_line); fprintf (ps_file, "%%%%EndProlog\n\n"); /* Start the first page of the output */ fprintf (ps_file, "%%%%Page: 1 1\n\n"); fprintf (ps_file, "gsave\n\n"); if (template -> page == LANDSCAPE) { fprintf (ps_file, "612 0 translate\n90 rotate\n\n"); } /* Check whether the description text should be printed in the header */ if (template -> description) used_lines = POST_Print_Header (description, max_line); else used_lines = 0; /* Set the desired line thickness for drawing boxes, underlines ... */ thickness = 0.05 * max_line; fprintf (ps_file, "%f setlinewidth\n\n", 0.05 * max_line); /* Now proceed to generate the alignment output information */ position = 0; /* Starting position for traversing output buffers */ current_box = template -> boxes; current_underline = template -> underlines; position_lines = NULL; label_set = FALSE; POST_All (used_lines, template, dim, size, buffers); } /* After the postscript output has been generated, close PostScript file */ fprintf (ps_file, "%%%%Trailer\n"); fprintf (ps_file, "%%%%Pages: %d\n\n", pages); if (direction == FILE_OUT) fclose (ps_file); } /*****************************************************************************/ /* */ /* Internal procedures of the POST(Script) display module */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Procedure: POST_MaxFont_Front */ /* */ /* Procedure finds the maximal font size for any requested banner */ /* information; returns the font size (default font if either no banner */ /* is requested or all banners have NULL font information) */ int POST_MaxFont_Front (instance_ptr template) { txt_ptr txt; int max; max = 0; txt = template -> texts; while (txt != NULL) { if ((txt -> banner) && (txt -> banner_size > max)) max = txt -> banner_size; txt = txt -> next; } if (max == 0) max = DEFAULT_BANNER_FONT; return max; } /*****************************************************************************/ /* */ /* Procedure: POST_MaxFont_Line */ /* */ /* Procedure finds the maximal requested font size for any sequence text */ /* line; returns the font size (default font if there are no */ /* specifications */ int POST_MaxFont_Line (instance_ptr template) { txt_ptr txt; int max; max = 0; txt = template -> texts; while (txt != NULL) { if (txt -> font > max) max = txt -> font; txt = txt -> next; } if (max == 0) max = DEFAULT_TEXT_FONT; return max; } /*****************************************************************************/ /* */ /* Procedure: POST_MaxFont_Trail */ /* */ /* Procedure finds the maximal font size for any requested trailer */ /* information; returns the font size (default font if either no trailer */ /* is requested or all trailers have NULL font information) */ int POST_MaxFont_Trail (instance_ptr template) { txt_ptr txt; int max; max = 0; txt = template -> texts; while (txt != NULL) { if ((txt -> trailer) && (txt -> trailer_size > max)) max = txt -> trailer_size; txt = txt -> next; } if (max == 0) max = DEFAULT_TRAILER_FONT; return max; } /*****************************************************************************/ /* */ /* Procedure: POST_Print_Header */ /* */ /* Procedure formats the description header information in PostScript and */ /* outputs it to PostScript definition file */ int POST_Print_Header (char *description, int max_line) { char head_buff [MAX_CHAR_WIDTH], *line, *scan, *trn; bool end_hit; int used, cpy; /* Set the header font first, before doing any printing */ fprintf (ps_file, "/Courier findfont %d scalefont setfont\n\n", max_line); /* Courier font selected for header due to any info. that may be tabulated */ /* Now move to the beginning of the page, to start the header */ fprintf (ps_file, "%d %d moveto\n", left_x, top_y - down_skip); /* Proceed to loop for each line of the header, outputing the line */ used = 0; line = scan = description; end_hit = FALSE; while (!end_hit) { if (line != scan) { *scan = '\n'; scan++; } while ((*scan != '\0') && (*scan != '\n')) scan++; if (*scan == '\0') end_hit = TRUE; else *scan = '\0'; /* Now copy the line, inserting 'escape' characters where necessary */ cpy = 0; trn = line; while (*trn != '\0') { if ((*trn == ')') || (*trn == '(')) { head_buff [cpy++] = '\\'; head_buff [cpy++] = *trn; } else head_buff [cpy++] = *trn; trn++; } head_buff [cpy] = '\0'; line = scan + 1; /* Now output the current line of the header text */ fprintf (ps_file, "(%s) show\n", head_buff); used++; fprintf (ps_file, "%d %d %d sub moveto\n", left_x, top_y, (used + 1) * max_line); } used += 2; /* Add two blank lines at the end of the header description */ fprintf (ps_file, "\n"); return used; } /*****************************************************************************/ /* */ /* Procedure: POST_Set_Variables */ /* */ /* Procedure generates PostScript code to evaluate values of all PostScript */ /* parameters not reachable from C, to be used later */ void POST_Set_Variables (int margin, int max_front, int max_line) { if (page_position == LANDSCAPE) { fprintf (ps_file, "612 0 translate\n90 rotate\n\n"); } /* Variables "buc_width" and "buc_height" give with and height of line char.*/ fprintf (ps_file, "/Courier findfont %d scalefont setfont\n\n", max_line); fprintf (ps_file, "newpath\n0 0 moveto\n(X) false charpath flattenpath\n"); fprintf (ps_file, "pathbbox /flf exch def pop pop pop\n\n"); fprintf (ps_file, "/fract {flf 10 div} def\n"); fprintf (ps_file, "/buc_height {flf fract add} def\n\n"); /* fprintf (ps_file, "newpath\n0 0 moveto\n(X) true charpath flattenpath\n"); fprintf (ps_file, "pathbbox pop /buc_width exch def pop pop\n\n"); */ fprintf (ps_file, "0 0 moveto\n(X) stringwidth\npop /buc_width exch def\n\n"); /* Variables "second_x" and "third_x" give the starting X positions for the */ /* actual sequence text and trailer information */ if (front_size == 0) { fprintf (ps_file, "/second_x %d def\n", left_x); fprintf (ps_file, "/third_x {buc_width %d mul %d add} def\n\n", margin + 2, left_x); } else { fprintf (ps_file, "/Courier findfont %d scalefont setfont\n\n", max_front); /* fprintf (ps_file, "newpath\n0 0 moveto\n(X) true charpath flattenpath\n"); fprintf (ps_file, "pathbbox pop pop pop /flen exch def\n\n"); */ fprintf (ps_file, "0 0 moveto\n(X) stringwidth\npop /flen exch def\n\n"); fprintf (ps_file, "/second_x {flen 9 mul %d add} def\n", left_x); fprintf (ps_file, "/third_x {buc_width %d mul second_x add} def\n\n", margin + 2); } if (page_position == LANDSCAPE) { fprintf (ps_file, "-90 rotate\n-612 0 translate\n\n"); } } /*****************************************************************************/ /* */ /* Procedure: POST_All */ /* */ /* Procedure verifies if the next block of information can fit to the */ /* current page of output, and then either places the block or finalizes */ /* the current page; next block is positioned by recursive invocation of */ /* this procedure (tail recursion with global variables) */ void POST_All (int used, instance_ptr template, int dim, long int size, Buffer_Vector *buffers) { int vertical, index; long int scanpos; bool line_empty, can_fit; /* Calculate first how many lines are contained in the block that follows */ vertical = 0; for (index = 0; index < dim; index++) { if ((buffers [index]).code == TEXT_LINE) { if (( (buffers [index]).trim == ALWAYS_CODE) || (( (buffers [index]).trim == ONSTART_CODE) && (position + template -> margins > (buffers [index]).start_text) && ( (buffers [index]).valid)) || (( (buffers [index]).trim == UNTILEND_CODE) && (position <= (buffers [index]).end_text) && ( (buffers [index]).valid)) || (( (buffers [index]).valid) && (position + template -> margins > (buffers [index]).start_text) && (position <= (buffers [index]).end_text))) vertical++; } else { /* Examine whether the line is completely empty */ line_empty = TRUE; for (scanpos = 0; (scanpos + position < size) && (scanpos < template -> margins); scanpos++) if (((buffers [index]).buffer) [position + scanpos] != ' ') line_empty = FALSE; if (!line_empty) vertical++; } } /* Estimate whether current block representing alignment can fit to page */ if (used + vertical <= page_lines) can_fit = TRUE; else can_fit = FALSE; if (can_fit) { POST_Put_Block (used, vertical, template, dim, size, buffers); used = used + vertical + template -> breaklines; } else { /* Next block can not fit to the current page */ POST_Conclude_Page (buffers, size); used = 0; } /* Examine whether there are any more blocks to be printed */ if (position < size) POST_All (used, template, dim, size, buffers); else POST_Conclude_Page (buffers, size); } /*****************************************************************************/ /* */ /* Procedure: POST_Put_Block */ /* */ /* Procedure generates PostScript code to output a single block of alignment */ /* information, with respect to the received settings */ void POST_Put_Block (int used, int vertical, instance_ptr template, int dim, long int size, Buffer_Vector *buffers) { pos_ptr temp, prev; int line, index, jota, scanner; bool show; long int scanpos, local_count; char banner_buffer [10], seq_buffer [MAX_CHAR_WIDTH]; txt_ptr text_record; /* First form a record for the current block - it will be needed for boxes */ temp = (pos_ptr) ckalloc (sizeof (Position_Struct)); temp -> position = position; /* Position in buffers where this block starts */ temp -> line = used + 1; temp -> vertical = vertical; temp -> last_crippled = -1; /* Last line in this block assumed not partial */ temp -> next = NULL; /* Add the record for the current block to the list of blocks on the page */ if (position_lines == NULL) position_lines = temp; else { prev = position_lines; while (prev -> next != NULL) prev = prev -> next; prev -> next = temp; } /* Now proceed to output the lines of the block */ line = used + 1; for (index = 0; index < dim; index++) { /* Determine first whether the line should be displayed at all */ show = FALSE; /* Assume not to be shown, verify otherwise */ if ((buffers [index]).code == TEXT_LINE) { if (( (buffers [index]).trim == ALWAYS_CODE) || (( (buffers [index]).trim == ONSTART_CODE) && (position + template -> margins > (buffers [index]).start_text) && ( (buffers [index]).valid)) || (( (buffers [index]).trim == UNTILEND_CODE) && (position <= (buffers [index]).end_text) && ( (buffers [index]).valid)) || (( (buffers [index]).valid) && (position + template -> margins > (buffers [index]).start_text) && (position <= (buffers [index]).end_text))) show = TRUE; /* Examine now whether the line is "crippled", to be shown but it has */ /* blanks in the area to be shown - this information will be used to */ /* reduce the size of any box potentially present in this line */ if (show) { if (( (buffers [index]).trim == ALWAYS_CODE) || (( (buffers [index]).trim == ONSTART_CODE) && (position > (buffers [index]).start_text)) || (( (buffers [index]).trim == UNTILEND_CODE) && (position + template -> margins < (buffers [index]).end_text)) || ((position > (buffers [index]).start_text) && (position + template -> margins < (buffers [index]).end_text))) temp -> last_crippled = -1; else { temp -> last_crippled = -1; for (jota = position; (temp -> last_crippled == -1) && (jota < size) && (jota < position + template -> margins); jota++) if ((buffers [index]).buffer [jota] == ' ') temp -> last_crippled = index; } } } else { /* Examine whether the line is completely empty */ temp -> last_crippled = -1; for (scanpos = 0; (scanpos + position < size) && (scanpos < template -> margins); scanpos++) if (((buffers [index]).buffer) [position + scanpos] != ' ') show = TRUE; else temp -> last_crippled = index; } if (show) { /* This line is to be shown, so proceed with it */ if ((buffers [index]).code == TEXT_LINE) { text_record = (txt_ptr) ((buffers [index]).record); /* Generate the code to calculate the position to start the text */ fprintf (ps_file, "%d %d %d sub moveto\n", left_x, top_y, line * down_skip); /* Examine whether there is banner information comming with text - show */ if (front_size > 0) { /* Examine whether this line has a banner */ if ((buffers [index]).banner) { sprintf (banner_buffer, "%6ld: ", (buffers [index]).start_sequence); } else { /* Banner generally set, but not for this line */ sprintf (banner_buffer, " "); } /* Generate the code to produce the banner information output */ if (text_record -> banner_font == NULL) { if (text_record -> banner_size == 0) { fprintf (ps_file, "/Courier findfont %d scalefont setfont\n", DEFAULT_BANNER_FONT); } else { fprintf (ps_file, "/Courier findfont %d scalefont setfont\n", text_record -> banner_size); } } else { if (text_record -> banner_size == 0) { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", text_record -> banner_font, DEFAULT_BANNER_FONT); } else { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", text_record -> banner_font, text_record -> banner_size); } } fprintf (ps_file, "(%s) show\n\n", banner_buffer); } /* Now output the actual line contents */ fprintf (ps_file, "second_x %d %d sub moveto\n", top_y, line * down_skip); if (text_record -> font == 0) { fprintf (ps_file, "/Courier findfont %d scalefont setfont\n", DEFAULT_TEXT_FONT); } else { fprintf (ps_file, "/Courier findfont %d scalefont setfont\n", text_record -> font); } /* Pack the buffer of text information for display */ local_count = 0; for (scanner = 0; (scanner < template -> margins) && (position + scanner < size); scanner++) { seq_buffer [scanner] = ((buffers [index]).buffer) [position + scanner]; if ((((buffers [index]).buffer) [position + scanner] != '-') && (((buffers [index]).buffer) [position + scanner] != ' ')) ((buffers [index]).start_sequence)++; local_count++; } seq_buffer [local_count] = '\0'; fprintf (ps_file, "(%s) show\n\n", seq_buffer); /* Examine whether the line has trailer information, display if it has */ if ((buffers [index]).seq_name != NULL) { fprintf (ps_file, "third_x %d %d sub moveto\n", top_y, line * down_skip); if (text_record -> trailer_font == NULL) { if (text_record -> trailer_size == 0) { fprintf (ps_file, "/Times-Bold findfont %d scalefont setfont\n", DEFAULT_TRAILER_FONT); } else { fprintf (ps_file, "/Times-Bold findfont %d scalefont setfont\n", text_record -> trailer_size); } } else { if (text_record -> trailer_size == 0) { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", text_record -> trailer_font, DEFAULT_TRAILER_FONT); } else { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", text_record -> trailer_font, text_record -> trailer_size); } } fprintf (ps_file, "(%s) show\n\n", (buffers [index]).seq_name); } } else { /* Line is not a text line */ /* Output the line contents */ fprintf (ps_file, "second_x %d %d sub moveto\n", top_y, line * down_skip); fprintf (ps_file, "/Courier findfont %d scalefont setfont\n", text_font); local_count = 0; for (scanner = 0; (scanner < template -> margins) && (position + scanner < size); scanner++) { seq_buffer [scanner] = ((buffers [index]).buffer) [position + scanner]; local_count++; } seq_buffer [local_count] = '\0'; fprintf (ps_file, "(%s) show\n\n", seq_buffer); } line++; } } position += local_count; } /*****************************************************************************/ /* */ /* Procedure: POST_Conclude_Page */ /* */ /* Procedure performs all actions to be done before the actual output is */ /* done, generates the output command and resets all page-dependent */ /* state variables */ void POST_Conclude_Page (Buffer_Vector *buffers, long int size) { pos_ptr scan, trash; POST_Boxes (buffers, size); /* Place all boxes to be drawn on this page */ POST_Underlines (buffers, size); /* Place underlines to be drawn on page */ fprintf (ps_file, "showpage\n\n"); /* Require the page output */ /* Finally, do the reset of all page dependent information */ scan = position_lines; /* Destroy the list of block positions for the page */ while (scan != NULL) { trash = scan; scan = scan -> next; free (trash); } position_lines = NULL; pages++; /* Yet another page has been prepared */ fprintf (ps_file, "grestore\n\n"); /* Prepare positioning of next page (if "landscape", then it has to rotate) */ if (position < size) { /* There is still contents to be printed */ fprintf (ps_file, "%%%%Page: %d %d\n\n", pages + 1, pages + 1); fprintf (ps_file, "gsave\n\n"); if (page_position == LANDSCAPE) fprintf (ps_file, "612 0 translate\n90 rotate\n\n"); fprintf (ps_file, "%f setlinewidth\n\n", thickness); } } /*****************************************************************************/ /* */ /* Procedure: POST_Boxes */ /* */ /* Procedure to position all boxes enclosing text on the current page */ void POST_Boxes (Buffer_Vector *buffers, long int size) { ibox_ptr place_box; place_box = current_box; while ((place_box != NULL) && (place_box -> position < position)) { POST_Place_Single_Box (place_box, buffers, size); place_box = place_box -> next; } /* Now advance current box pointer to skip all boxes that are fully shown */ while ((current_box != NULL) && (current_box -> position + current_box -> width <= position)) current_box = current_box -> next; } /*****************************************************************************/ /* */ /* Procedure: POST_Underlines */ /* */ /* Procedure to draw all underlines required at the page */ void POST_Underlines (Buffer_Vector *buffers, long int size) { iunder_ptr place_under; place_under = current_underline; while ((place_under != NULL) && (place_under -> position < position)) { POST_Place_Single_Underline (place_under, buffers, size); place_under = place_under -> next; } /* Now advance current underline pointer to skip all those fully shown */ while ((current_underline != NULL) && (current_underline -> position + current_underline -> length <= position)) current_underline = current_underline -> next; } /*****************************************************************************/ /* */ /* Procedure: POST_Place_Single_Box */ /* */ /* Procedure to place a single box on the current page, with respect to its */ /* settings and positions that are represented on the page */ void POST_Place_Single_Box (ibox_ptr box, Buffer_Vector *buffers, long int size) { pos_ptr scan; int linenum, height, buffnum; bool empty; long int searcher; int jota, reduce; /* Traverse the list of blocks represented on the page to draw box at pos. */ scan = position_lines; /* Start with the first block represented on page */ while ((scan != NULL) && (scan -> position + margin <= box -> position)) scan = scan -> next; if (scan != NULL) { /* So there is overlap of this block with the box */ while ((scan != NULL) && /* For each block this box is in */ (scan -> position < box -> position + box -> width)) { /* Calculate correct line number and the height for this block */ if (first_tickmarks) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan -> position; (searcher < (scan -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { linenum = (scan -> line) + 1; height = (scan -> vertical) - 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan -> position; (searcher < (scan -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { linenum++; height--; } } } else { linenum = scan -> line; height = scan -> vertical; } } else { linenum = scan -> line; height = scan -> vertical; } /* Examine if the box has already started or whether it ends in the block */ if (scan -> position > box -> position) { /* Already started */ if (scan -> position + margin < box -> position + box -> width) { /* Box does not end in the current line - open at both ends */ POST_Draw_Box3 (1, margin, linenum, height, box -> style); /* Try to place the label at the box, if there was one requested */ if ((!label_set) && (box -> mark != NO_LABEL)) POST_Draw_Label (box, scan -> vertical, buffers, size); } else { /* Box open at start, but ending in the block */ if (scan -> last_crippled > 0) { /* Adjust the height for last line */ reduce = 1; for (jota = scan -> position; jota < box -> position + box -> width; jota++) if ((buffers [scan -> last_crippled]).buffer [jota] != ' ') reduce = 0; height = height - reduce; } POST_Draw_Box1 (1, (box -> position) + (box -> width) - (scan -> position), linenum, height, box -> style); /* Try to place the label at the box, if there was one requested */ if ((!label_set) && (box -> mark != NO_LABEL)) POST_Draw_Label (box, scan -> vertical, buffers, size); } } else { /* Box not open at starts - beginning within this block */ if (scan -> position + margin < box -> position + box -> width) { /* Box does not end in the current line - open at the end */ if (scan -> last_crippled > 0) { /* Adjust the height for last line */ reduce = 1; for (jota = box -> position; jota < scan -> position + margin; jota++) if ((buffers [scan -> last_crippled]).buffer [jota] != ' ') reduce = 0; height = height - reduce; } POST_Draw_Box2 ((box -> position) - (scan -> position) + 1, margin, linenum, height, box -> style); /* Place the label at the box, if there was one requested */ if (box -> mark != NO_LABEL) POST_Draw_Label (box, scan -> vertical, buffers, size); } else { /* Box is completely contained in this block */ if (scan -> last_crippled > 0) { /* Adjust the height for last line */ reduce = 1; for (jota = box -> position; jota < box -> position + box -> width; jota++) if ((buffers [scan -> last_crippled]).buffer [jota] != ' ') reduce = 0; height = height - reduce; } POST_Draw_Box0 ((box -> position) - (scan -> position) + 1, (box -> position) + (box -> width) - (scan -> position), linenum, height, box -> style); /* Place the label at the box, if there was one requested */ if (box -> mark != NO_LABEL) POST_Draw_Label (box, scan -> vertical, buffers, size); } } scan = scan -> next; } label_set = FALSE; } } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Box0 */ /* */ /* Draw a complete, closed box at the specified position */ void POST_Draw_Box0 (long int from, long int to, int line, int height, char *style) { /* Set PostScript variables up_lx & up_ly to the right position on the page */ POST_Set_Point (line, (int) from); /* Now create the path for this box and draw its outline */ fprintf (ps_file, "gsave\n\n"); fprintf (ps_file, "/x_ext {buc_width %d mul} def\n", (int) (to - from + 1)); fprintf (ps_file, "/y_ext {%d %d mul buc_height add %d add} def\n\n", down_skip, height - 1, 2 + (int) (down_skip / 10)); if (style != NULL) fprintf (ps_file, "%s setdash\n\n", style); fprintf (ps_file, "newpath\n"); fprintf (ps_file, "up_lx up_ly moveto\n"); fprintf (ps_file, "up_lx x_ext add up_ly lineto\n"); fprintf (ps_file, "up_lx x_ext add up_ly y_ext sub lineto\n"); fprintf (ps_file, "up_lx up_ly y_ext sub lineto\n"); fprintf (ps_file, "up_lx up_ly lineto\n"); fprintf (ps_file, "stroke\n\n"); fprintf (ps_file, "grestore\n\n"); } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Box1 */ /* */ /* Draw box open-ended at left, but closed to the right, at the given pos. */ void POST_Draw_Box1 (long int from, long int to, int line, int height, char *style) { /* Set PostScript variables up_lx & up_ly to the right position on the page */ POST_Set_Point (line, (int) from); /* Now create the path for this box and draw its outline */ fprintf (ps_file, "gsave\n\n"); fprintf (ps_file, "/x_ext {buc_width %d mul} def\n", (int) (to - from + 1)); fprintf (ps_file, "/y_ext {%d %d mul buc_height add %d add} def\n\n", down_skip, height -1, 2 + (int) (down_skip / 10)); if (style != NULL) fprintf (ps_file, "%s setdash\n\n", style); fprintf (ps_file, "newpath\n"); fprintf (ps_file, "up_lx up_ly moveto\n"); fprintf (ps_file, "up_lx x_ext add up_ly lineto\n"); fprintf (ps_file, "up_lx x_ext add up_ly y_ext sub lineto\n"); fprintf (ps_file, "up_lx up_ly y_ext sub lineto\n"); fprintf (ps_file, "stroke\n\n"); fprintf (ps_file, "grestore\n\n"); } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Box2 */ /* */ /* Draw a box closed at left, but open-ended at right, at specified position */ void POST_Draw_Box2 (long int from, long int to, int line, int height, char *style) { /* Set PostScript variables up_lx & up_ly to the right position on the page */ POST_Set_Point (line, (int) from); /* Now create the path for this box and draw its outline */ fprintf (ps_file, "gsave\n\n"); fprintf (ps_file, "/x_ext {buc_width %d mul} def\n", (int) (to - from + 1)); fprintf (ps_file, "/y_ext {%d %d mul buc_height add %d add} def\n\n", down_skip, height - 1, 2 + (int) (down_skip / 10)); if (style != NULL) fprintf (ps_file, "%s setdash\n\n", style); fprintf (ps_file, "newpath\n"); fprintf (ps_file, "up_lx x_ext add up_ly moveto\n"); fprintf (ps_file, "up_lx up_ly lineto\n"); fprintf (ps_file, "up_lx up_ly y_ext sub lineto\n"); fprintf (ps_file, "up_lx x_ext add up_ly y_ext sub lineto\n"); fprintf (ps_file, "stroke\n\n"); fprintf (ps_file, "grestore\n\n"); } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Box3 */ /* */ /* Draw a box open-ended at both sides (so it's two parallel lines) at the */ /* specified position on the page */ void POST_Draw_Box3 (long int from, long int to, int line, int height, char *style) { /* Set PostScript variables up_lx & up_ly to the right position on the page */ POST_Set_Point (line, (int) from); /* Now create the path for this box and draw its outline */ fprintf (ps_file, "gsave\n\n"); fprintf (ps_file, "/x_ext {buc_width %d mul} def\n", (int) (to - from + 1)); fprintf (ps_file, "/y_ext {%d %d mul buc_height add %d add} def\n\n", down_skip, height - 1, 2 + (int) (down_skip / 10)); if (style != NULL) fprintf (ps_file, "%s setdash\n\n", style); fprintf (ps_file, "newpath\n"); fprintf (ps_file, "up_lx up_ly moveto\n"); fprintf (ps_file, "up_lx x_ext add up_ly lineto\n"); fprintf (ps_file, "up_lx up_ly y_ext sub moveto\n"); fprintf (ps_file, "up_lx x_ext add up_ly y_ext sub lineto\n"); fprintf (ps_file, "stroke\n\n"); fprintf (ps_file, "grestore\n\n"); } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Label */ /* */ /* Procedure draws a label for the received box at the right position on the */ /* page, if label was requested */ void POST_Draw_Label (ibox_ptr box, int height, Buffer_Vector *buffers, long int size) { long int pivot_point; pos_ptr scan_pos; int line, offset, buffnum; bool empty; long int searcher; /* Verify first if all information needed to draw a label has been received */ if (box -> label == NULL) { fprintf (stderr, "PROBLEM: Label request with no label.\n"); } else { /* Proceed to draw the label */ /* Actions depend on where label is to be positioned with respect to box */ switch (box -> mark) { case LEFT_POSITION: { /* Label at the left side of the box */ /* Find the position for the label first */ pivot_point = box -> position; if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (box -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Now proceed to set correct line_x & line_y variables; do the move */ fprintf (ps_file, "/line_x {up_lx 1 add} def\n"); if (box -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else /* Label to be placed below the block */ fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (box -> label); label_set = TRUE; } break; } case CENTERED_POSITION: { /* Find the position for the label first */ pivot_point = (box -> position) + (long int) ((box -> width) / 2); if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (box -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Store the width of the label string into PostScript s_width variable */ POST_Set_String_Width (box -> label); /* Check whether the width of the box for the label is even or odd */ if (((long int) ((box -> width) / 2)) * 2 == box -> width) { /* Even */ fprintf (ps_file, "/line_x {up_lx s_width 2 div sub} def\n"); } else { /* Box width is odd - do the adjustments */ fprintf (ps_file, "/line_x {up_lx s_width 2 div sub buc_width 2 div add} def\n"); } if (box -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (box -> label); label_set = TRUE; } break; } case RIGHT_POSITION: { /* Find the position for the label first */ pivot_point = box -> position + box -> width; if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (box -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Store the width of the label string into PostScript s_width variable */ POST_Set_String_Width (box -> label); fprintf (ps_file, "/line_x {up_lx s_width sub 2 sub} def\n"); if (box -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (box -> label); label_set = TRUE; } break; } default: fprintf (stderr, "PROBLEM: Illegal box mark.\n"); } } } /*****************************************************************************/ /* */ /* Procedure: POST_Set_Point */ /* */ /* Procedure sets up PostScript variables up_lx and up_ly to point to the */ /* graphical x and y coordinates of the upper left corner of the character */ /* position given by its line and offset */ void POST_Set_Point (int line, int offset) { fprintf (ps_file, "/up_lx {buc_width %d mul second_x add} def\n", offset - 1); fprintf (ps_file, "/up_ly {%d %d sub buc_height add 1 add} def\n\n", top_y, down_skip * line); } /*****************************************************************************/ /* */ /* Procedure: POST_Place_Single_Underline */ /* */ /* Procedure to place a single underline on the current page, with respect */ /* to its settings and positions that are represented on the page */ void POST_Place_Single_Underline (iunder_ptr underline, Buffer_Vector *buffers, long int size) { pos_ptr scan; int linenum; /* Traverse the list of blocks represented on the page to draw underline */ scan = position_lines; /* Skip all blocks that precede the start of this underline */ while ((scan != NULL) && (scan -> position + margin <= underline -> position)) scan = scan -> next; if (scan != NULL) { /* So there is overlap of this block with underline */ while ((scan != NULL) && (scan -> position < underline -> position + underline -> length)) { /* Calculate the number of the line in which underline is to be placed */ if ((linenum = POST_Underlined_Sequence (underline, scan -> position, (scan -> position) + margin - 1, buffers, size)) == 0) { sprintf (warning_buffer, "WARNING: Underline at [%ld, %ld] removed or truncated.\n", underline -> position, (underline -> position) + (underline -> length) - 1); CONT_Warning (warning_buffer); } else { /* Underline OK, sequence line number adjusted */ linenum = (scan -> line) + linenum - 1; /* Examine if underline has already started or whether it ends in block */ if (scan -> position > underline -> position) { /* Already started */ if (scan -> position + margin < underline -> position + underline -> length) { /* The whole line in this block is underlined - side to side */ POST_Draw_Underline (1, margin, linenum, underline -> kind, underline -> style); } else { /* Underline from beginning, but not to the end */ POST_Draw_Underline (1, (underline -> position) + (underline -> length) - (scan -> position), linenum, underline -> kind, underline -> style); } } else { /* Underline begins within this block */ if (scan -> position + margin < underline -> position + underline -> length) { /* Underline does not end in the current line - goes right to the end */ POST_Draw_Underline ((underline -> position) - (scan -> position) + 1, margin, linenum, underline -> kind, underline -> style); } else { /* Underline is completely contained in this block */ POST_Draw_Underline ((underline -> position) - (scan -> position) + 1, (underline -> position) + (underline -> length) - (scan -> position), linenum, underline -> kind, underline -> style); } } /* Check if a label is to be placed above this underline, and place */ if ((!label_set) && (underline -> mark != NO_LABEL)) { POST_Label_Underline (underline, scan -> vertical, buffers, size); } } scan = scan -> next; } label_set = FALSE; } } /*****************************************************************************/ /* */ /* Procedure: POST_Draw_Underline */ /* */ /* Draw an underline at the specified position on the page */ void POST_Draw_Underline (long int from, long int to, int line, int kind, char *style) { /* Set PostScript variables up_lx & up_ly to the right position on the page */ POST_Set_Point (line, (int) from); /* Now create the path for this underline and draw it */ fprintf (ps_file, "gsave\n\n"); fprintf (ps_file, "/x_ext {buc_width %d mul} def\n", (int) (to - from + 1)); fprintf (ps_file, "/y_pos {up_ly buc_height sub %d sub} def\n", 2 + (int) (down_skip / 10)); if (style != NULL) fprintf (ps_file, "%s setdash\n\n", style); fprintf (ps_file, "newpath\n"); fprintf (ps_file, "up_lx y_pos moveto\n"); fprintf (ps_file, "up_lx x_ext add y_pos lineto\n"); if (kind == DOUBLE_UNDERLINE) { fprintf (ps_file, "up_lx y_pos %d sub moveto\n", (int) (down_skip / 10) + 1); fprintf (ps_file, "up_lx x_ext add y_pos %d sub lineto\n", (int) (down_skip / 10) + 1); } fprintf (ps_file, "stroke\n\n"); fprintf (ps_file, "grestore\n\n"); } /*****************************************************************************/ /* */ /* Procedure: POST_Underlined_Sequence */ /* */ /* Given an underline record and positional parameters, procedure determines */ /* the exact line in the block where the underline should be placed; */ /* returns line number in the block where the underline should be placed, */ /* if it should be placed at all, or 0 if it should not */ int POST_Underlined_Sequence (iunder_ptr rec, long int from, long int to, Buffer_Vector *buffers, long int size) { int adjustment, seq, index; bool visible; long int pos; /* Loop for each line in the buffer to locate underlined info and adjust */ adjustment = 0; seq = 0; index = 0; while (seq != rec -> text_line) { /* Until target line passed */ if ((buffers [index]).code == TEXT_LINE) { seq++; /* Another text line encountered */ if ((buffers [index]).trim == ALWAYS_CODE) visible = TRUE; else if (( (buffers [index]).trim == ONSTART_CODE) && ( (buffers [index]).valid) && (to >= (buffers [index]).start_text)) visible = TRUE; else if (( (buffers [index]).trim == UNTILEND_CODE) && (from <= (buffers [index]).end_text) && ( (buffers [index]).valid)) visible = TRUE; else if (( (buffers [index]).valid) && (to >= (buffers [index]).start_text) && (from <= (buffers [index]).end_text)) visible = TRUE; else visible = FALSE; if (!visible) adjustment--; } else { /* Current line is not text line */ visible = FALSE; for (pos = from; (pos <= to) && (((buffers [index]).buffer) [pos] != '\0'); pos++) if (((buffers [index]).buffer) [pos] != ' ') visible = TRUE; if (visible) adjustment++; } index++; } /* Last visibility indicator is giving visibility of line to be underlined */ if (!visible) return 0; else return rec -> text_line + adjustment; } /*****************************************************************************/ /* */ /* Procedure: POST_Label_Underline */ /* */ /* Procedure draws a label for the received underline at the right position */ /* on the page, if label was requested */ void POST_Label_Underline (iunder_ptr underline, int height, Buffer_Vector *buffers, long int size) { long int pivot_point; pos_ptr scan_pos; int line, offset, buffnum; bool empty; long int searcher; /* Verify first if all information needed to draw a label has been received */ if (underline -> label == NULL) { fprintf (stderr, "PROBLEM: Label request with no label.\n"); } else { /* Proceed to draw the label */ /* Actions depend on where label is to be positioned above the top line */ switch (underline -> mark) { case LEFT_POSITION: { /* Label at the left side of the underline */ /* Find the position for the label first */ pivot_point = underline -> position; if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (underline -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Now proceed to set correct line_x & line_y variables; do the move */ fprintf (ps_file, "/line_x {up_lx 1 add} def\n"); if (underline -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (underline -> label); label_set = TRUE; } break; } case CENTERED_POSITION: { /* Find the position for the label first */ pivot_point = (underline -> position) + (long int) ((underline -> length) / 2); if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (underline -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Store the width of the label string into PostScript s_width variable */ POST_Set_String_Width (underline -> label); /* Check whether the length of underline for the label is even or odd */ if (((long int) ((underline -> length) / 2)) * 2 == underline -> length) { /* Even */ fprintf (ps_file, "/line_x {up_lx s_width 2 div sub} def\n"); } else { /* Underline length is odd - do the adjustments */ fprintf (ps_file, "/line_x {up_lx s_width 2 div sub buc_width 2 div add} def\n"); } if (underline -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (underline -> label); label_set = TRUE; } break; } case RIGHT_POSITION: { /* Find the position for the label first */ pivot_point = underline -> position + underline -> length; if ((pivot_point >= position_lines -> position) && (pivot_point < position)) { /* Is the label on this page? */ /* Find the line and the offset for the pivot position of the label */ scan_pos = position_lines; while ((scan_pos -> next != NULL) && ((scan_pos -> next) -> position <= pivot_point)) scan_pos = scan_pos -> next; if ((first_tickmarks) && (underline -> label_place == UP_LABEL)) { empty = TRUE; if (count_added) buffnum = 1; else buffnum = 0; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [buffnum]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) { line = scan_pos -> line + 1; if (count_added) { /* Count data present? */ empty = TRUE; for (searcher = scan_pos -> position; (searcher < (scan_pos -> position) + margin) && (searcher < size); searcher++) if (((buffers [0]).buffer) [searcher] != ' ') empty = FALSE; if (!empty) line++; } } else line = scan_pos -> line; } else line = scan_pos -> line; offset = (int) (pivot_point - (scan_pos -> position) + 1); POST_Set_Point (line, offset); /* Set PostScript variables */ /* Store the width of the label string into PostScript s_width variable */ POST_Set_String_Width (underline -> label); fprintf (ps_file, "/line_x {up_lx s_width sub 2 sub} def\n"); if (underline -> label_place == UP_LABEL) fprintf (ps_file, "/line_y {up_ly 2 add} def\n"); else fprintf (ps_file, "/line_y {up_ly %d sub buc_height sub 2 sub} def\n", height * down_skip); fprintf (ps_file, "line_x line_y moveto\n\n"); /* And, after the position is set, proceed to write the label */ POST_Assemble_Label (underline -> label); label_set = TRUE; } break; } default: fprintf (stderr, "PROBLEM: Illegal underline mark.\n"); } } } /*****************************************************************************/ /* */ /* Procedure: POST_Set_String_Width */ /* */ /* Procedure calculates the total width of composite-font labels into */ /* PostScript variable s_width */ void POST_Set_String_Width (label_ptr label) { label_ptr current; /* Set the initial string width to 0, then add widths of all fragments */ fprintf (ps_file, "/s_width 0 def\n\n"); for (current = label; current != NULL; current = current -> next) { if ((current -> font_name == NULL) || (current -> font_size <= 0)) fprintf (stderr, "PROBLEM: Font for label fragment missing.\n"); else if (current -> text == NULL) fprintf (stderr, "PROBLEM: Label fragment text missing.\n"); else { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", current -> font_name, current -> font_size); fprintf (ps_file, "newpath\n0 0 moveto\n(%s) true charpath flattenpath\n", current -> text); fprintf (ps_file, "pathbbox pop /s_supl exch def pop pop\n"); fprintf (ps_file, "/s_add {s_width s_supl add} def\n"); fprintf (ps_file, "/s_width s_add def\n\n"); } } } /*****************************************************************************/ /* */ /* Procedure: POST_Assemble_Label */ /* */ /* Procedure for drawing multiple-font labels. All positioning parameters */ /* are assumed to be already set */ void POST_Assemble_Label (label_ptr label) { label_ptr current; for (current = label; current != NULL; current = current -> next) { if ((current -> font_name == NULL) || (current -> font_size <= 0)) fprintf (stderr, "PROBLEM: Font for label fragment missing.\n"); else if (current -> text == NULL) fprintf (stderr, "PROBLEM: Label fragment text missing.\n"); else { fprintf (ps_file, "/%s findfont %d scalefont setfont\n", current -> font_name, current -> font_size); fprintf (ps_file, "(%s) show\n", current -> text); } } fprintf (ps_file, "\n"); }