1 /* Copyright (c) 1999, 2000, 2002, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
4 /* Functions related to walking through strings, to get each character
5 * in turn, along with any font/size changes and horizontal/vertical
6 * motions that should be done before printing that character.
14 /* when entering pile, adjust size by PILE_A / PILE_B and when
15 * exiting pile, adjust by the recipocal of that. */
20 /* This structure contains information about one line in a set of lines
21 * that are piled on top of one another. This might be used for figured
22 * bass or superscript/subscript or things like that. */
24 char *text
; /* points to start of piled line */
25 short align_offset
; /* where the alignment is, relative to text */
26 short length
; /* bytes in this line */
27 short last_char_offset
; /* where the last character is */
28 short last_digit_offset
;/* where the last digit is */
29 float width_left_of_align
; /* width for this line */
30 float width_right_of_align
;
31 struct PILED_LINE
*next
;/* the next line in the pile */
34 /* This keep track of an entire piled section of a string */
36 float curr_x
, curr_y
; /* where we are now, relative to pile start */
37 struct PILED_LINE
*lines_p
; /* list of lines in pile */
38 struct PILED_LINE
*curr_line_p
; /* which piled line we're processing */
39 short curr_offset
; /* offset into curr_line_p->text */
40 float width_left_of_align
; /* width of the entire pile */
41 float width_right_of_align
;
42 short orig_font
; /* font coming into the pile */
43 short orig_size
; /* size coming into the pile */
44 short new_size
; /* size at beginning of pile */
45 char *pile_end
; /* last character of pile */
48 /* One of these structs is passed to get_piled() with the current
49 * font and size filled in. If we are in piled mode, it will return 1 and
50 * will have filled in all the field. Otherwise it will return 0.
56 char ch
; /* the next character in the pile, or \0 if
57 * this only indicates motion */
58 double hor
; /* how much to adjust before printing ch */
59 double vert
; /* how much to adjust before printing ch */
62 /* When a backspace is returned, this keeps track of its width, to
63 * potentially be returned via backsp_width() */
64 static int Backspace_dist
;
66 /* This is all the info about the piled section we are currently processing.
67 * We only deal with one pile at a time, so a single static structure
69 static struct PILED Pile_info
;
71 static void begin_pile
P((struct PILE_INFO
*pile_info_p
));
72 static char *prep_pile
P((char *string
, struct PILE_INFO
*pile_info_p
));
73 static int get_piled
P((struct PILE_INFO
*pile_info_p
));
74 static double vert_distance
P((int vert_arg
, int font
, int size
));
77 /* When a STR_PILE is encountered, this should be called to gather all
78 * the information we might need about how to align everything in the pile.
79 * Then other functions like get_piled() can be called to retrieve info.
80 * The passed-in pile_info_p contains the font and size at the beginning
81 * of the pile, and on return will contain the new size and the vertical
82 * and horizontal offsets before the first character of the pile.
83 * Return value points to the last character that was processed from string.
87 prep_pile(string
, pile_info_p
)
89 char *string
; /* place in string where piling begins */
90 struct PILE_INFO
*pile_info_p
; /* passed in font and size, returns size and vert */
93 struct PILED_LINE
**piled_line_p_p
; /* where to link on next line */
94 struct PILED_LINE
*line_p
; /* the current line of pile */
95 char *s
; /* to walk through string */
96 int alignments
= 0; /* how many align points found */
97 int lines
= 0; /* how many lines in pile */
98 float width_contribution
; /* width of current char */
99 int i
; /* index though a line */
100 int orig_i
; /* value of i when current
101 * character began (some
102 * things take up multiple
103 * bytes and we need to know
108 Pile_info
.width_left_of_align
= Pile_info
.width_right_of_align
= 0.0;
109 Pile_info
.lines_p
= (struct PILED_LINE
*) 0;
110 Pile_info
.curr_line_p
= (struct PILED_LINE
*) 0;
111 Pile_info
.curr_offset
= 0;
112 piled_line_p_p
= &(Pile_info
.lines_p
);
113 line_p
= *piled_line_p_p
;
115 Pile_info
.orig_font
= font
= pile_info_p
->font
;
117 /* Adjust size for entering the pile */
118 size
= Pile_info
.new_size
= pile_size(pile_info_p
->size
, NO
);
120 /* Walk through the piled things, skipping past the initial STR_PILE,
121 * this time just to find the line boundaries and alignment offsets. */
122 for (s
= string
+ 1; *s
!= '\0'; s
++) {
124 /* if end piling, jump out */
126 curr_char
= *s
& 0xff;
127 if ( curr_char
== STR_PILE
|| curr_char
== STR_BOX_END
128 || curr_char
== STR_CIR_END
) {
129 if (line_p
!= (struct PILED_LINE
*) 0) {
130 line_p
->length
= s
- line_p
->text
;
132 line_p
= (struct PILED_LINE
*) 0;
137 /* If we don't have a current PILED_LINE struct,
138 * get one, and initialize it. */
139 if (line_p
== (struct PILED_LINE
*) 0) {
140 MALLOC(PILED_LINE
, *piled_line_p_p
, 1);
141 line_p
= *piled_line_p_p
;
143 line_p
->align_offset
= -1;
144 line_p
->last_digit_offset
= -1;
145 line_p
->last_char_offset
= -1;
147 line_p
->width_left_of_align
= 0.0;
148 line_p
->width_right_of_align
= 0.0;
149 line_p
->next
= (struct PILED_LINE
*) 0;
157 /* Point the offset at the following character,
158 * because for C_ALIGN that character will straddle
159 * the alignment point, and we can easily make
160 * L_ALIGN work with that convention too. */
161 line_p
->align_offset
= s
- line_p
->text
+ 1;
166 /* if newline, finish this line by saving its length,
167 * then prepare for next line by moving the place at
168 * which to add a line to the current line's 'next' */
169 line_p
->length
= s
- line_p
->text
;
170 piled_line_p_p
= &(line_p
->next
);
171 line_p
= (struct PILED_LINE
*) 0;
178 /* need to skip past its argument byte */
184 /* Mark as last character so far, in case we need
185 * to use that as default alignment */
186 line_p
->last_char_offset
= s
- line_p
->text
;
187 /* need to skip past its 2 argument bytes */
193 /* We actually don't allow this, but can get to this
194 * code in error cases. Skip past argument. */
199 /* Mark as last character so far, in case we need
200 * to use that as default alignment */
201 line_p
->last_char_offset
= s
- line_p
->text
;
203 /* remember location of last digit, in case we
204 * need to use as default aligment */
206 line_p
->last_digit_offset
= s
- line_p
->text
;
212 if (*s
== '\0' && line_p
!= (struct PILED_LINE
*) 0) {
213 line_p
->length
= s
- line_p
->text
;
216 /* if there are lines with unspecified alignment points, find them */
217 if (alignments
< lines
) {
218 for (line_p
= Pile_info
.lines_p
;
219 line_p
!= (struct PILED_LINE
*) 0;
220 line_p
= line_p
->next
) {
221 /* If no user-specified alignment point in this line,
222 * use last digit if any, else last char. If there was
223 * no last char (empty line, maybe to get subscript
224 * without superscript, for example) this will end
225 * up with an offset of -1. */
226 if (line_p
->align_offset
< 0) {
227 line_p
->align_offset
=
228 ((line_p
->last_digit_offset
>= 0)
229 ? line_p
->last_digit_offset
230 : line_p
->last_char_offset
);
235 /* Find left and right of alignment for each line and the
236 * widest overall for the pile. */
237 for (line_p
= Pile_info
.lines_p
;
238 line_p
!= (struct PILED_LINE
*) 0;
239 line_p
= line_p
->next
) {
241 /* Some items take more than one byte. In that case,
242 * the index 'i' in this 'for' loop will get more added to it
243 * than just the increment at the end of each loop.
244 * When this happens, orig_i keeps track of where the
245 * multi-byte item began. */
246 for (i
= 0; i
< line_p
->length
; i
++) {
249 width_contribution
= 0.0;
251 switch (line_p
->text
[i
] & 0xff) {
255 /* get its width and skip past its args */
256 width_contribution
+= width(
257 str2mfont(line_p
->text
[i
] & 0xff),
264 /* Remember the font, may need for getting
265 * widths of future characters */
266 font
= line_p
->text
[++i
];
270 /* remember the size, may need for getting
271 * widths of future characters */
272 size
= line_p
->text
[++i
];
278 /* irrelevant for width, no args */
282 /* irrelevant for width, 1 byte arg to skip */
287 width_contribution
-= ((line_p
->text
[++i
] *
288 size
) / DFLT_SIZE
) / BACKSP_FACTOR
;
295 /* not relevant here */
300 /* we don't really know how wide this will
301 * end up being, so just use the width of
302 * the following byte (% or #).
304 width_contribution
= width(font
, size
,
308 if ( IS_STR_COMMAND(line_p
->text
[i
]) & 0xff) {
309 pfatal("unexpected STR_ value 0x%x in prep_pile()",
310 line_p
->text
[i
] & 0xff);
313 /* ordinary character, look up its width */
314 width_contribution
= width(font
, size
,
319 /* Figure out which side of alignment.
320 * Anything before align_offset goes on left,
321 * while anything after goes on the right.
322 * If we're right at the alignment offset,
323 * and the alignment type is STR_C_ALIGN,
324 * split the width. Otherwise goes on right. */
325 if (orig_i
< line_p
->align_offset
) {
326 line_p
->width_left_of_align
327 += width_contribution
;
329 else if (orig_i
== line_p
->align_offset
&&
330 (line_p
->text
[orig_i
- 1] & 0xff)
332 /* put half on each side */
333 width_contribution
/= 2.0;
334 line_p
->width_left_of_align
335 += width_contribution
;
336 line_p
->width_right_of_align
337 += width_contribution
;
340 line_p
->width_right_of_align
341 += width_contribution
;
345 /* find widest line */
346 if (line_p
->width_left_of_align
347 > Pile_info
.width_left_of_align
) {
348 Pile_info
.width_left_of_align
349 = line_p
->width_left_of_align
;
351 if (line_p
->width_right_of_align
352 > Pile_info
.width_right_of_align
) {
353 Pile_info
.width_right_of_align
354 = line_p
->width_right_of_align
;
358 /* start at first character of first line of pile */
359 begin_pile(pile_info_p
);
361 Pile_info
.pile_end
= s
;
366 /* fill in the fields of pile_info_p for starting at the beginning of
367 * the current pile. */
370 begin_pile(pile_info_p
)
372 struct PILE_INFO
*pile_info_p
;
375 /* begin at first line of pile */
376 Pile_info
.curr_line_p
= Pile_info
.lines_p
;
377 Pile_info
.curr_offset
= -1;
379 /* if user ended a string with a pile indicator (which is a bit
380 * silly, but could happen...) get out now,
381 * to avoid dereferencing a line that doesn't exist. */
382 if (Pile_info
.curr_line_p
== (struct PILED_LINE
*) 0) {
386 /* fill in rest of returned data */
387 pile_info_p
->hor
= Pile_info
.curr_x
= Pile_info
.width_left_of_align
388 - Pile_info
.lines_p
->width_left_of_align
;
389 /* Adjust vertical by half the unpiled line height, but less a little
390 * (there is some white space padding, usually piles are numbers
391 * without descenders, and they are smaller anyway, so looks better
392 * to jam things together a bit more than normal). */
393 pile_info_p
->vert
= Pile_info
.curr_y
394 = fontheight(Pile_info
.orig_font
, Pile_info
.orig_size
) / 2.0
395 - POINT
* Pile_info
.new_size
/ DFLT_SIZE
;
396 pile_info_p
->size
= Pile_info
.new_size
;
398 pile_info_p
->ch
= '\0';
402 /* Get the next character in piled segment, along with any horizontal
403 * and/or vertical motion that should be done before printing that
404 * character. Info is placed into the struct passed in. If the returned
405 * ->ch is '\0', that means this call only returned motion information.
406 * Returns NO at end of pile, otherwise YES.
410 get_piled(pile_info_p
)
412 struct PILE_INFO
*pile_info_p
;
415 char *text
= 0; /* Piled text to process. The initialization
416 * is just to avoid bogus "used before set"
417 * warning. It will always get set to a real
418 * string before actually being used. */
419 float backdist
; /* width of backspace */
420 int mfont
; /* FONT_MUSIC* */
423 /* Move on to next character. */
424 ++(Pile_info
.curr_offset
);
426 if (Pile_info
.curr_line_p
!= (struct PILED_LINE
*) 0) {
428 /* Check if we've gotten to end of pile. We are if we're
429 * past the last character of the last line of the pile */
430 if (Pile_info
.curr_line_p
->next
== (struct PILED_LINE
*) 0 &&
431 Pile_info
.curr_offset
432 >= Pile_info
.curr_line_p
->length
) {
433 /* yes, at end of pile */
434 Pile_info
.curr_line_p
= (struct PILED_LINE
*) 0;
437 text
= Pile_info
.curr_line_p
->text
;
441 /* check for end of pile */
442 if (Pile_info
.curr_line_p
== (struct PILED_LINE
*) 0) {
444 /* Adjust vertical and horizontal to past pile.
445 * Horizontal adjust is the total width of the
446 * pile minus where we are currently. */
447 pile_info_p
->hor
= (Pile_info
.width_left_of_align
448 + Pile_info
.width_right_of_align
)
450 /* Vertical adjust is the negative of the current
451 * y, since that gets us back to zero relative to
452 * where we started. */
453 pile_info_p
->vert
= - (Pile_info
.curr_y
);
455 /* Restore size for leaving the pile. */
456 pile_info_p
->size
= pile_size(pile_info_p
->size
, YES
);
458 /* mark as not being an actual character, just motion */
459 pile_info_p
->ch
= '\0';
464 /* handle newline -- go to next line of pile */
465 if (text
[Pile_info
.curr_offset
] == '\n') {
466 /* prepare for next line, if any */
467 Pile_info
.curr_line_p
= Pile_info
.curr_line_p
->next
;
468 Pile_info
.curr_offset
= -1;
470 /* Adjust vertical and horizontal to start next line of pile.
471 * For horizontal, go back to beginning of pile,
472 * then add the difference between this line's
473 * left of align and the pile's. */
474 if (Pile_info
.curr_line_p
!= (struct PILED_LINE
*) 0) {
475 pile_info_p
->hor
= - Pile_info
.curr_x
;
476 Pile_info
.curr_x
= Pile_info
.width_left_of_align
477 - Pile_info
.curr_line_p
->width_left_of_align
;
478 pile_info_p
->hor
+= Pile_info
.curr_x
;
480 /* vertical is adjusted by height of font, less
481 * a little to jam together to look better. */
482 pile_info_p
->vert
= - fontheight(pile_info_p
->font
,
484 + POINT
* pile_info_p
->size
/ DFLT_SIZE
;
485 Pile_info
.curr_y
+= pile_info_p
->vert
;
488 pile_info_p
->vert
= pile_info_p
->hor
= 0.0;
492 pile_info_p
->ch
= '\0';
497 pile_info_p
->hor
= pile_info_p
->vert
= 0.0;
499 switch (text
[Pile_info
.curr_offset
] & 0xff) {
503 mfont
= str2mfont( text
[Pile_info
.curr_offset
] & 0xff);
504 pile_info_p
->font
= mfont
;
505 pile_info_p
->size
= text
[Pile_info
.curr_offset
+1];
506 pile_info_p
->ch
= text
[Pile_info
.curr_offset
+2];
507 Pile_info
.curr_x
+= width(mfont
,
508 pile_info_p
->size
, pile_info_p
->ch
);
509 Pile_info
.curr_offset
+= 2;
513 (Pile_info
.curr_offset
)++;
514 pile_info_p
->font
= text
[Pile_info
.curr_offset
];
515 pile_info_p
->ch
= '\0';
519 (Pile_info
.curr_offset
)++;
520 pile_info_p
->size
= text
[Pile_info
.curr_offset
];
521 pile_info_p
->ch
= '\0';
525 pile_info_p
->ch
= (char) STR_SLASH
;
530 pile_info_p
->ch
= '\0';
534 (Pile_info
.curr_offset
)++;
535 pile_info_p
->vert
= vert_distance(
536 DECODE_VERT(text
[Pile_info
.curr_offset
]),
537 pile_info_p
->font
, pile_info_p
->size
);
538 pile_info_p
->ch
= '\0';
542 (Pile_info
.curr_offset
)++;
543 Backspace_dist
= text
[Pile_info
.curr_offset
];
544 backdist
= backsp_width(pile_info_p
->size
);
545 pile_info_p
->hor
-= backdist
;
546 Pile_info
.curr_x
-= backdist
;
547 pile_info_p
->ch
= '\0';
552 /* These aren't really allowed in piles,
553 * but we can hit this code under some error cases,
554 * so we recognize them and do something reasonable.
556 (Pile_info
.curr_offset
)++;
557 pile_info_p
->ch
= text
[Pile_info
.curr_offset
];
561 if ( IS_STR_COMMAND(text
[Pile_info
.curr_offset
]) & 0xff) {
562 pfatal("unexpected STR_ value 0x%x in get_piled()",
563 text
[Pile_info
.curr_offset
] & 0xff);
566 /* ordinary character */
567 Pile_info
.curr_x
+= width(pile_info_p
->font
,
569 text
[Pile_info
.curr_offset
]);
570 pile_info_p
->ch
= text
[Pile_info
.curr_offset
];
579 /* given a pointer into a string, return the code for the next
580 * character in the string. This will be either the ASCII code
581 * or the music symbol code. This function will also update the
582 * pointer into the string and the font and size if appropriate.
583 * If there happens to be a music character in the middle of a string,
584 * the font (and maybe size) will temporarily be changed for the music
585 * font. This function keeps track of that.
587 * Restrictions: This function must be used by calling it on the beginning
588 * of a string, then to walk through that string. You don't have to go all the
589 * way to the end of a given string, but once you switch to a new string
590 * (from which you must begin at its beginning) you cannot go back to the
591 * middle of some other string that you had been working on before.
593 * This function calls the more general function which can also update
594 * vertical motion and alignment information. It is retained for backward
595 * compatibility for the places that don't care about those things.
599 next_str_char(str_p_p
, font_p
, size_p
)
601 char **str_p_p
; /* address of pointer into string. Will be incremented
602 * to beyond current character on return (this might
603 * be several bytes into the string if current char
604 * is a special string command */
605 int *font_p
; /* pointer to font. Will be updated to new font if
607 int *size_p
; /* pointer to size. Will be updated to new size if
611 /* place to hold things we don't care about from general function */
612 double dummy_vertical
, dummy_horizontal
;
616 return(nxt_str_char(str_p_p
, font_p
, size_p
, &dummy_textfont
,
617 &dummy_vertical
, &dummy_horizontal
, &dummy_in_pile
, NO
));
621 /* returns the next character in string, along with any font/size changes
622 * and horizontal/vertical motions that should happen before that character.
626 nxt_str_char(str_p_p
, font_p
, size_p
, textfont_p
, vertical_p
, horizontal_p
, in_pile_p
, slash
)
631 int *textfont_p
; /* font disregarding music characters */
632 double *vertical_p
; /* if non-zero, do vertical motion */
633 double *horizontal_p
; /* if non-zero, do horizontal motion */
634 int *in_pile_p
; /* will be set to YES if inside a pile */
635 int slash
; /* if YES, return any STR_SLASH's found,
636 * else ignore them */
639 static char *prev_str_p
; /* most recent value of *str_p_p */
640 static int textfont
; /* current font, ignoring music chars */
641 static int textsize
; /* current size, ignoring music chars */
642 static int pile_mode
; /* if inside a pile */
644 struct PILE_INFO pile_info
;
646 /* initialize to assume no vertical motion or alignment at this char */
647 *horizontal_p
= *vertical_p
= 0.0;
649 if (*str_p_p
== (char *) 0) {
655 if (prev_str_p
!= *str_p_p
) {
656 /* must be starting on a different string. Our
657 * remembered text font/size are no longer valid */
659 *textfont_p
= textfont
;
664 if (pile_mode
== YES
) {
665 /* call the special function for piled to get next */
666 pile_info
.font
= textfont
;
667 pile_info
.size
= textsize
;
668 pile_mode
= get_piled(&pile_info
);
670 /* save what it returned */
671 *font_p
= pile_info
.font
;
672 *size_p
= pile_info
.size
;
673 if (pile_info
.font
!= FONT_MUSIC
) {
674 textfont
= pile_info
.font
;
675 *textfont_p
= textfont
;
676 textsize
= pile_info
.size
;
679 /* Add motion to any accumulated so far */
680 *vertical_p
+= pile_info
.vert
;
681 *horizontal_p
+= pile_info
.hor
;
683 if (pile_info
.ch
== '\0') {
684 /* only motion this time, keep going */
687 else if ( (pile_info
.ch
& 0xff) == STR_SLASH
&&
689 /* caller doesn't care about slashes */
693 *in_pile_p
= pile_mode
;
694 return (pile_info
.ch
);
699 if (**str_p_p
== '\0') {
706 if ( ! IS_STR_COMMAND(**str_p_p
)) {
707 /* just an ordinary character. Return it after updating
708 * pointer to point past it */
709 code
= **str_p_p
& 0xff;
711 prev_str_p
= *str_p_p
;
713 /* if last chacter was music character, put back real * font and size */
714 if (IS_MUSIC_FONT(*font_p
)) {
721 /* special command. see which one */
722 switch ( (unsigned) (**str_p_p
& 0xff) ) {
725 /* change font to specified font and point past it */
726 *font_p
= *++(*str_p_p
);
729 *textfont_p
= textfont
;
733 /* change size to specified size and point past it */
734 *size_p
= *++(*str_p_p
);
740 /* Page number and number of pages are strange cases.
741 * We don't necessarily know at this point
742 * how many digits long they will be. So we punt:
743 * just return % or #. For height, ascent, and descent,
744 * the % or # will be the same as any number
745 * of digits (or at least close enough, we hope).
746 * That means the only problem is when we are getting
747 * the width of a string or actually printing
748 * it, so we'll deal with those as special cases */
750 prev_str_p
= *str_p_p
;
754 prev_str_p
= *str_p_p
;
760 /* music character */
761 *font_p
= str2mfont( (unsigned) (**str_p_p
& 0xff) );
762 *size_p
= *++(*str_p_p
);
763 code
= (*++(*str_p_p
)) & 0xff;
765 prev_str_p
= *str_p_p
;
769 Backspace_dist
= (*++(*str_p_p
)) & 0xff;
771 prev_str_p
= *str_p_p
;
790 *vertical_p
+= vert_distance(
791 DECODE_VERT( *++(*str_p_p
) ),
802 pile_info
.font
= textfont
;
803 pile_info
.size
= textsize
;
804 *str_p_p
= prep_pile(*str_p_p
, &pile_info
);
805 *vertical_p
+= pile_info
.vert
;
806 *horizontal_p
+= pile_info
.hor
;
807 *size_p
= pile_info
.size
;
814 prev_str_p
= *str_p_p
;
821 pfatal("bad internal format for string (%x)",
826 prev_str_p
= *str_p_p
;
831 /* Given an argument to STR_VERTICAL and a font and size,
832 * return the distance in inches to move vertically. */
835 vert_distance(vert_arg
, font
, size
)
844 /* first convert to ratio relative to font height */
846 ratio
= (double) vert_arg
/ (double) MAXVERTICAL
;
849 ratio
= (double) vert_arg
/ (double) (-MINVERTICAL
);
851 return(ratio
* fontheight(font
, size
));
855 /* return width of most recent backspace returned by next_str_char() */
860 int size
; /* adjust to this point size */
863 return ( (double) Backspace_dist
* ((double) size
/ (double) DFLT_SIZE
)
868 /* Return width of current pile */
874 return(Pile_info
.width_left_of_align
+ Pile_info
.width_right_of_align
);
878 /* adjust size when entering/leaving a pile. Called with current size and
879 * whether we are entering or leaving. It returns the new size. */
882 pile_size(size
, in_pile
)
884 int size
; /* current size */
885 int in_pile
; /* if YES, we are currently in a pile and are about to leave
886 * it; if NO, we are about to enter the pile */
892 /* entering pile. Save current size, and return new size */
893 Pile_info
.orig_size
= size
;
894 /* constrain new size to be at least MINSIZE */
895 if ((Pile_info
.new_size
= PILE_A
* size
/ PILE_B
) < MINSIZE
) {
896 Pile_info
.new_size
= MINSIZE
;
898 return(Pile_info
.new_size
);
902 /* Restore size. If we're still at the size at the beginning
903 * of the pile, use the orginal value before the pile to avoid
904 * any possible roundoff errors going back and forth,
905 * otherwise adjust by inverse of the factor used when
906 * entering the pile. */
907 if (size
== Pile_info
.new_size
) {
908 return(Pile_info
.orig_size
);
911 if ((new_size
= (size
* PILE_B
) / PILE_A
) > MAXSIZE
) {
912 /* constrain to no larger than MAXSIZE */
921 /* given where a pile begins and the font/size at that point, return the
922 * width from the beginning to the pile to the alignment point of the pile. */
925 align_distance(string
, font
, size
)
927 char *string
; /* pile starts here */
932 struct PILE_INFO pile_info
;
934 pile_info
.font
= font
;
935 pile_info
.size
= size
;
936 (void) prep_pile(string
, &pile_info
);
937 return(Pile_info
.width_left_of_align
);