1 /* adjustment buffer for putting words into lines */
7 #define ADJ_LLEN(a) MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
10 struct wb wbs
[NWORDS
]; /* words in buf */
11 int gaps
[NWORDS
]; /* gaps before words */
13 int wid
; /* total width of buf */
14 int swid
; /* current space width */
15 int gap
; /* space before the next word */
16 int nls
; /* newlines before the next word */
17 int l
, i
, t
; /* current .l, .i and ti */
18 int ll
, li
, lt
; /* current line's .l, .i and ti */
19 int filled
; /* filled all words in the last adj_fill() */
22 void adj_ll(struct adj
*adj
, int ll
)
27 void adj_ti(struct adj
*adj
, int ti
)
32 void adj_in(struct adj
*adj
, int in
)
37 /* .ll, .in and .ti are delayed until the partial line is output */
38 static void adj_confupdate(struct adj
*adj
)
46 /* does the adjustment buffer need to be flushed without filling? */
47 static int adj_fullnf(struct adj
*a
)
49 /* blank lines; indented lines; newlines when buffer is empty */
50 return a
->nls
> 1 || (a
->nls
&& a
->gap
) ||
51 (a
->nls
- a
->filled
> 0 && !a
->nwords
);
54 /* does the adjustment buffer need to be flushed? */
55 int adj_full(struct adj
*a
, int fill
)
58 return a
->nls
- a
->filled
> 0;
61 return a
->nwords
&& a
->wid
> ADJ_LLEN(a
);
64 /* is the adjustment buffer empty? */
65 int adj_empty(struct adj
*a
, int fill
)
67 return !fill
? a
->nls
- a
->filled
<= 0 : !a
->nwords
&& !adj_fullnf(a
);
71 void adj_swid(struct adj
*adj
, int swid
)
76 /* move words inside an adj struct */
77 static void adj_movewords(struct adj
*a
, int dst
, int src
, int len
)
79 memmove(a
->wbs
+ dst
, a
->wbs
+ src
, len
* sizeof(a
->wbs
[0]));
80 memmove(a
->gaps
+ dst
, a
->gaps
+ src
, len
* sizeof(a
->gaps
[0]));
83 static int adj_linewid(struct adj
*a
, int n
)
86 for (i
= 0; i
< n
; i
++)
87 w
+= wb_wid(&a
->wbs
[i
]) + a
->gaps
[i
];
91 static int adj_linefit(struct adj
*a
, int llen
)
94 for (i
= 0; i
< a
->nwords
; i
++) {
95 w
+= wb_wid(&a
->wbs
[i
]) + a
->gaps
[i
];
102 /* move n words from the adjustment buffer to s */
103 static int adj_move(struct adj
*a
, int n
, struct sbuf
*s
, int *els_neg
, int *els_pos
)
110 for (i
= 0; i
< n
; i
++) {
112 sbuf_printf(s
, "%ch'%du'", c_ec
, a
->gaps
[i
]);
113 sbuf_append(s
, sbuf_buf(&cur
->sbuf
));
114 w
+= wb_wid(cur
) + a
->gaps
[i
];
115 if (cur
->els_neg
< *els_neg
)
116 *els_neg
= cur
->els_neg
;
117 if (cur
->els_pos
> *els_pos
)
118 *els_pos
= cur
->els_pos
;
124 adj_movewords(a
, 0, n
, a
->nwords
);
125 a
->wid
= adj_linewid(a
, a
->nwords
);
126 if (a
->nwords
) /* apply the new .l and .i */
131 /* try to hyphenate the n-th word */
132 static void adj_hyph(struct adj
*a
, int n
, int w
, int hyph
)
135 int flg
= hyph
| (n
? 0 : HY_ANY
);
138 if (wb_hyph(&a
->wbs
[n
], w
, &w1
, &w2
, flg
)) {
143 adj_movewords(a
, n
+ 2, n
+ 1, a
->nwords
- n
);
145 memcpy(&a
->wbs
[n
], &w1
, sizeof(w1
));
146 memcpy(&a
->wbs
[n
+ 1], &w2
, sizeof(w2
));
149 a
->wid
= adj_linewid(a
, a
->nwords
);
152 /* fill and copy a line into s */
153 int adj_fill(struct adj
*a
, int ad_b
, int fill
, int hyph
, struct sbuf
*s
,
154 int *ll
, int *in
, int *ti
, int *els_neg
, int *els_pos
)
156 int adj_div
, adj_rem
;
159 int llen
= ADJ_LLEN(a
);
163 if (!fill
|| adj_fullnf(a
)) {
166 return adj_move(a
, a
->nwords
, s
, els_neg
, els_pos
);
168 n
= adj_linefit(a
, llen
);
170 adj_hyph(a
, n
, llen
- adj_linewid(a
, n
) - a
->gaps
[n
], hyph
);
171 n
= adj_linefit(a
, llen
);
174 w
= adj_linewid(a
, n
);
176 adj_div
= (llen
- w
) / (n
- 1);
177 adj_rem
= (llen
- w
) % (n
- 1);
178 for (i
= 0; i
< n
- 1; i
++)
179 a
->gaps
[i
+ 1] += adj_div
+ (i
< adj_rem
);
181 w
= adj_move(a
, n
, s
, els_neg
, els_pos
);
183 a
->wid
-= a
->gaps
[0];
185 a
->filled
= n
&& !a
->nwords
;
189 void adj_sp(struct adj
*adj
)
191 adj
->gap
+= adj
->swid
;
194 void adj_nl(struct adj
*adj
)
200 /* ignore the previous newline */
201 void adj_nonl(struct adj
*adj
)
204 adj
->gap
+= adj
->swid
;
208 static void adj_word(struct adj
*adj
, struct wb
*wb
)
210 int i
= adj
->nwords
++;
211 wb_init(&adj
->wbs
[i
]);
212 adj
->gaps
[i
] = adj
->filled
? 0 : adj
->gap
;
214 adj
->wid
+= wb_wid(wb
) + adj
->gap
;
215 wb_cat(&adj
->wbs
[i
], wb
);
218 static int adj_eos(struct adj
*adj
)
220 return adj
->nwords
&& wb_eos(&adj
->wbs
[adj
->nwords
- 1]);
223 /* insert wb into the adjustment buffer */
224 void adj_wb(struct adj
*adj
, struct wb
*wb
)
226 if (wb_empty(wb
) || adj
->nwords
== NWORDS
)
228 if (!adj
->nwords
) /* apply the new .l and .i */
230 if (adj
->nls
&& !adj
->gap
&& adj
->nwords
>= 1)
231 adj
->gap
= adj_eos(adj
) ? adj
->swid
* 2 : adj
->swid
;
237 struct adj
*adj_alloc(void)
239 struct adj
*adj
= malloc(sizeof(*adj
));
240 memset(adj
, 0, sizeof(*adj
));
244 void adj_free(struct adj
*adj
)
249 int adj_wid(struct adj
*adj
)
251 return adj
->wid
+ (adj
->nls
? adj
->swid
: adj
->gap
);