ref: 5c7624e050d8559ee996b251fc063a5df07d9d46
dir: /line.c/
#include <stdlib.h>
#include <string.h>
#include "xroff.h"
/* horizontal and vertical line characters */
static char *hs[] = {"_", "\\_", "\\-", "\\(ru", "\\(ul", "\\(rn", NULL};
static char *vs[] = {"\\(bv", "\\(br", "|", NULL};
static int cwid(char *c)
{
struct glyph *g = dev_glyph(c, n_f);
return charwid(g ? g->wid : SC_DW, n_s);
}
static int lchar(char *c, char **cs)
{
while (*cs)
if (!strcmp(*cs++, c))
return 1;
return 0;
}
static void vmov(struct adj *adj, int w)
{
adj_put(adj, w, "\\v'%du'", w);
}
static void hmov(struct adj *adj, int w)
{
adj_put(adj, w, "\\h'%du'", w);
}
void ren_hline(struct adj *adj, char *arg)
{
char *lc = "\\(ru";
int w, l, n, i, rem;
l = eval_up(&arg, 0, 'm');
if (!l)
return;
if (arg[0] == '\\' && arg[1] == '&') /* \& can be used as a separator */
arg += 2;
if (*arg)
lc = arg;
w = cwid(lc);
/* negative length; moving backwards */
if (l < 0) {
hmov(adj, l);
l = -l;
}
n = l / w;
rem = l % w;
/* length less than character width */
if (l < w) {
n = 1;
rem = 0;
hmov(adj, -(w - l) / 2);
}
/* the initial gap */
if (rem) {
if (lchar(lc, hs)) {
adj_put(adj, w, "%s", lc);
hmov(adj, rem - w);
} else {
hmov(adj, rem);
}
}
for (i = 0; i < n; i++)
adj_put(adj, w, lc);
/* moving back */
if (l < w)
hmov(adj, -(w - l + 1) / 2);
}
void ren_vline(struct adj *adj, char *arg)
{
char *lc = "\\(br";
int w, l, n, i, rem, hw, neg;
l = eval_up(&arg, 0, 'm');
if (!l)
return;
neg = l < 0;
if (arg[0] == '\\' && arg[1] == '&') /* \& can be used as a separator */
arg += 2;
if (*arg)
lc = arg;
w = SC_HT; /* character height */
hw = cwid(lc); /* character width */
/* negative length; moving backwards */
if (l < 0) {
vmov(adj, l);
l = -l;
}
n = l / w;
rem = l % w;
/* length less than character width */
if (l < w) {
n = 1;
rem = 0;
vmov(adj, -w + l / 2);
}
/* the initial gap */
if (rem) {
if (lchar(lc, vs)) {
vmov(adj, w);
adj_put(adj, hw, "%s", lc);
hmov(adj, -hw);
vmov(adj, rem - w);
} else {
vmov(adj, rem);
}
}
for (i = 0; i < n; i++) {
vmov(adj, w);
adj_put(adj, hw, lc);
hmov(adj, -hw);
}
/* moving back */
if (l < w)
vmov(adj, l / 2);
if (neg)
vmov(adj, -l);
hmov(adj, hw);
}
static char *cutchar(char *d, char *s)
{
s = utf8get(d, s);
if (d[0] == '\\') {
s = utf8get(d + 1, s);
if (d[1] == '(') {
s = utf8get(d + 2, s);
s = utf8get(d + strlen(d), s);
}
}
return s;
}
static int maxwid(char *s)
{
char c[GNLEN * 4];
int w = 0;
while (*s) {
s = cutchar(c, s);
if (cwid(c) > w)
w = cwid(c);
}
return w;
}
static int nchars(char *s)
{
char c[GNLEN * 4];
int n = 0;
while (*s) {
s = cutchar(c, s);
n++;
}
return n;
}
void ren_bracket(struct adj *adj, char *arg)
{
char c[GNLEN * 4];
int ht, hc;
int w = maxwid(arg);
int n = nchars(arg);
ht = n * SC_HT;
hc = -(ht + SC_EM) / 2;
vmov(adj, hc + SC_HT);
while (*arg) {
arg = cutchar(c, arg);
adj_put(adj, cwid(arg), c);
hmov(adj, -cwid(c));
vmov(adj, SC_HT);
}
hmov(adj, w);
vmov(adj, hc);
}
void ren_over(struct adj *adj, char *arg)
{
char c[GNLEN * 4];
int a;
int w = maxwid(arg);
while (*arg) {
arg = cutchar(c, arg);
a = (w - cwid(c)) / 2;
hmov(adj, a);
adj_put(adj, cwid(arg), c);
hmov(adj, -cwid(c) - a);
}
hmov(adj, w);
}