dir: support text direction with .>>, .<<, \> and \<
[neatroff.git] / dir.c
blobaf652226473cf34fe655d7ad94a799952a3619f1
1 /* output text direction */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 int dir_do; /* enable text direction processing */
9 static char *dbuf; /* text in n_td direction */
10 static int dbuf_sz, dbuf_n; /* dbuf[] size and length */
11 static char *rbuf; /* text in (1 - n_td) direction */
12 static int rbuf_sz, rbuf_n; /* rbuf[] size and length */
13 static int dir_cd; /* current direction */
15 /* append s to the start (dir == 0) or end (dir == 1) of d */
16 static void dir_copy(char **d, int *d_n, int *d_sz, char *s, int s_n, int dir)
18 while (*d_n + s_n + 1 > *d_sz) {
19 int sz = *d_sz ? *d_sz * 2 : 512;
20 char *n = malloc(sz + 1);
21 if (*d_sz)
22 memcpy(dir ? n + *d_sz : n, *d, *d_sz);
23 free(*d);
24 *d_sz = sz;
25 *d = n;
27 if (dir > 0)
28 memcpy(*d + *d_sz - *d_n - s_n, s, s_n);
29 else
30 memcpy(*d + *d_n, s, s_n);
31 *d_n += s_n;
34 /* copy rbuf (the text in reverse direction) to dbuf */
35 static void dir_flush(void)
37 char *s = rbuf + (n_td > 0 ? 0 : rbuf_sz - rbuf_n);
38 dir_copy(&dbuf, &dbuf_n, &dbuf_sz, s, rbuf_n, n_td);
39 rbuf_n = 0;
42 /* append s to dbuf or rbuf based on the current text direction */
43 static void dir_append(char *s)
45 int dir = dir_cd > 0;
46 if (dir == n_td && rbuf_n)
47 dir_flush();
48 if (dir == n_td)
49 dir_copy(&dbuf, &dbuf_n, &dbuf_sz, s, strlen(s), dir);
50 else
51 dir_copy(&rbuf, &rbuf_n, &rbuf_sz, s, strlen(s), dir);
54 static void setfont(int f)
56 char cmd[32];
57 sprintf(cmd, "%cf(%02d", c_ec, f);
58 if (f >= 0)
59 dir_append(cmd);
62 static void setsize(int s)
64 char cmd[32];
65 sprintf(cmd, s <= 99 ? "%cs(%02d" : "%cs[%d]", c_ec, s);
66 if (s >= 0)
67 dir_append(cmd);
70 static void setcolor(int m)
72 char cmd[32];
73 sprintf(cmd, "%cm[%s]", c_ec, clr_str(m));
74 if (m >= 0)
75 dir_append(cmd);
78 void dir_fix(struct sbuf *sbuf, char *src)
80 char cmd[ILNLEN];
81 char *prev_s = src;
82 char *r, *c;
83 int f = -1, s = -1, m = -1;
84 int t, n;
85 dir_cd = n_td;
86 while ((t = escread(&src, &c)) >= 0) {
87 cmd[0] = '\0';
88 switch (t) {
89 case 0:
90 case 'D':
91 case 'h':
92 case 'v':
93 case 'x':
94 memcpy(cmd, prev_s, src - prev_s);
95 cmd[src - prev_s] = '\0';
96 dir_append(cmd);
97 break;
98 case 'f':
99 n = atoi(c);
100 if (f != n) {
101 setfont(f);
102 f = n;
103 setfont(f);
105 break;
106 case 'm':
107 n = clr_get(c);
108 if (m != n) {
109 setcolor(m);
110 m = n;
111 setcolor(m);
113 break;
114 case 's':
115 n = atoi(c);
116 if (s != n) {
117 setsize(s);
118 s = n;
119 setsize(s);
121 break;
122 case 'X':
123 sprintf(cmd, "%c%c\x03%s\x03", c_ec, t, c);
124 dir_append(cmd);
125 break;
126 case '<':
127 setcolor(m);
128 setfont(f);
129 setsize(s);
130 dir_cd = 1;
131 setsize(s);
132 setfont(f);
133 setcolor(m);
134 break;
135 case '>':
136 setcolor(m);
137 setfont(f);
138 setsize(s);
139 dir_cd = 0;
140 setsize(s);
141 setfont(f);
142 setcolor(m);
143 break;
145 prev_s = src;
147 setcolor(m);
148 setfont(f);
149 setsize(s);
150 dir_flush();
151 r = n_td > 0 ? dbuf + dbuf_sz - dbuf_n : dbuf;
152 r[dbuf_n] = '\0';
153 dbuf_n = 0;
154 sbuf_append(sbuf, r);
157 void dir_done(void)
159 free(rbuf);
160 free(dbuf);