ren: support fields
[neatroff.git] / adj.c
blob11fe4a1a4e8f28e9c3bf683ff25b6ff0c372578b
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "xroff.h"
6 #define ADJ_LLEN(a) MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
8 struct word {
9 struct sbuf s;
10 int wid; /* word width */
11 int gap; /* the space before this word */
12 int els_neg; /* pre-extra line space */
13 int els_pos; /* post-extra line space */
16 struct adj {
17 struct word words[NWORDS]; /* words in buf */
18 int nwords;
19 int wid; /* total width of buf */
20 int swid; /* current space width */
21 int gap; /* space before the next word */
22 int nls; /* newlines before the next word */
23 int l, i, t; /* current .l, .i and ti */
24 int ll, li, lt; /* current line's .l, .i and ti */
27 void adj_ll(struct adj *adj, int ll)
29 adj->l = ll;
32 void adj_ti(struct adj *adj, int ti)
34 adj->t = ti;
37 void adj_in(struct adj *adj, int in)
39 adj->i = in;
42 /* .ll, .in and .ti are delayed until the partial line is output */
43 static void adj_confupdate(struct adj *adj)
45 adj->ll = adj->l;
46 adj->li = adj->i;
47 adj->lt = adj->t;
48 adj->t = -1;
51 /* does the adjustment buffer need to be flushed without filling? */
52 static int adj_fullnf(struct adj *a)
54 /* blank lines; indented lines; newlines when buffer is empty */
55 return a->nls > 1 || (a->nls && a->gap) || (a->nls && !a->nwords);
58 /* does the adjustment buffer need to be flushed? */
59 int adj_full(struct adj *a, int fill)
61 if (!fill)
62 return a->nls;
63 if (adj_fullnf(a))
64 return 1;
65 return a->wid > ADJ_LLEN(a);
68 /* is the adjustment buffer empty? */
69 int adj_empty(struct adj *a, int fill)
71 return !fill ? !a->nls : !a->nwords && !adj_fullnf(a);
74 /* set space width */
75 void adj_swid(struct adj *adj, int swid)
77 adj->swid = swid;
80 /* move n words from the adjustment buffer to s */
81 static int adj_move(struct adj *a, int n, struct sbuf *s, int *els_neg, int *els_pos)
83 struct word *cur;
84 int w = 0;
85 int i;
86 *els_neg = 0;
87 *els_pos = 0;
88 for (i = 0; i < n; i++) {
89 cur = &a->words[i];
90 sbuf_printf(s, "%ch'%du'", c_ec, cur->gap);
91 sbuf_append(s, sbuf_buf(&cur->s));
92 sbuf_done(&cur->s);
93 w += cur->wid + cur->gap;
94 if (cur->els_neg < *els_neg)
95 *els_neg = cur->els_neg;
96 if (cur->els_pos > *els_pos)
97 *els_pos = cur->els_pos;
99 if (!n)
100 return 0;
101 a->nwords -= n;
102 memmove(a->words, a->words + n, a->nwords * sizeof(a->words[0]));
103 a->wid -= w;
104 if (a->nwords) /* apply the new .l and .i */
105 adj_confupdate(a);
106 return w;
109 /* fill and copy a line into s */
110 int adj_fill(struct adj *a, int ad_b, int fill, struct sbuf *s,
111 int *ll, int *in, int *ti, int *els_neg, int *els_pos)
113 int adj_div, adj_rem;
114 int w = 0;
115 int i, n;
116 int llen = ADJ_LLEN(a);
117 *ll = a->ll;
118 *in = a->li;
119 *ti = a->lt;
120 if (!fill || adj_fullnf(a)) {
121 a->nls--;
122 return adj_move(a, a->nwords, s, els_neg, els_pos);
124 for (n = 0; n < a->nwords; n++) {
125 if (n && w + a->words[n].wid + a->words[n].gap > llen)
126 break;
127 w += a->words[n].wid + a->words[n].gap;
129 if (ad_b && n > 1 && n < a->nwords) {
130 adj_div = (llen - w) / (n - 1);
131 adj_rem = llen - w - adj_div * (n - 1);
132 a->wid += llen - w;
133 for (i = 0; i < n - 1; i++)
134 a->words[i + 1].gap += adj_div + (i < adj_rem);
136 w = adj_move(a, n, s, els_neg, els_pos);
137 if (a->nwords)
138 a->wid -= a->words[0].gap;
139 a->words[0].gap = 0;
140 return w;
143 void adj_sp(struct adj *adj)
145 adj->gap += adj->swid;
148 void adj_nl(struct adj *adj)
150 adj->nls++;
151 adj->gap = 0;
154 static void adj_word(struct adj *adj, struct wb *wb)
156 struct word *cur = &adj->words[adj->nwords++];
157 cur->wid = wb_wid(wb);
158 cur->gap = adj->gap;
159 adj->wid += cur->wid + adj->gap;
160 wb_getels(wb, &cur->els_neg, &cur->els_pos);
161 sbuf_init(&cur->s);
162 sbuf_append(&cur->s, sbuf_buf(&wb->sbuf));
163 wb_reset(wb);
166 /* insert wb into the adjustment buffer */
167 void adj_wb(struct adj *adj, struct wb *wb)
169 if (wb_empty(wb) || adj->nwords == NWORDS)
170 return;
171 if (!adj->nwords) /* apply the new .l and .i */
172 adj_confupdate(adj);
173 if (adj->nls && !adj->gap && adj->nwords >= 1)
174 adj->gap = adj->swid;
175 adj_word(adj, wb);
176 adj->nls = 0;
177 adj->gap = 0;
180 struct adj *adj_alloc(void)
182 struct adj *adj = malloc(sizeof(*adj));
183 memset(adj, 0, sizeof(*adj));
184 return adj;
187 void adj_free(struct adj *adj)
189 free(adj);
192 int adj_wid(struct adj *adj)
194 return adj->wid + (adj->nls ? adj->swid : adj->gap);