Hi Branden, Dave, and others,

I've been playing a bit with neatroff lately, and tried separating
alignment from adjustment that we've discussed here before. I am
attaching the (mostly complete) patch below.[1]

It adds new request .al (align) with possible arguments l, c, r,
while .ad now takes only b, p, k.[2]

I am looking for your opinions regarding this alternative behavior,
mostly in relation to https://savannah.gnu.org/bugs/?65954.
I assume the old behavior would be retained in compatibility mode,
but that isn't part of the patch yet.

I personally find it intriguing, but am not sure if it's worth the
breaking change.

To test it:
  git clone https://github.com/aligrudi/neatroff_make
  cd neatroff_make
  make init
  cd neatroff
  git apply path/to/patch
  cd ..
  make neat
  neatroff/roff -F. INPUT.tr | neatpost/pdf -F. -pa4 > OUTPUT.pdf

~ onf

[1] If anyone is wondering why not patch groff, besides the fact that
    I have zero experience with C++, neatroff's code base is just an
    order of magnitude easier to understand and navigate through.

[2] p = paragraph-at-once adjustment
    k = keshideh adjustment (used for Arabic script)

---8<--------------------------------------------------8<------------
>From 84cad1ef5d0ff568e3bbfe51f2134517ee1aa726 Mon Sep 17 00:00:00 2001
From: onf <o...@disroot.org>
Date: Fri, 10 Jan 2025 16:15:56 +0100
Subject: [PATCH neatroff] decouple alignment from adjustment (new request
 .al), remove .na mode

TODO: check behavior of \p
TODO: commit message
TODO: backwards compatibility
---
 fmt.c  |  4 ++--
 reg.c  |  8 +++++---
 ren.c  | 38 +++++++++++++++++++++----------------
 roff.h | 19 ++++++++++++-------
 tr.c   | 60 ++++++++++++++++++++++++++++++++++------------------------
 5 files changed, 76 insertions(+), 53 deletions(-)

diff --git a/fmt.c b/fmt.c
index ce48cb4..bf499b0 100644
--- a/fmt.c
+++ b/fmt.c
@@ -18,7 +18,7 @@
 
 #define FMT_LLEN(f)    MAX(0, (f)->ll - (f)->li - (f)->lI)
 #define FMT_FILL(f)    (!n_ce && n_u)
-#define FMT_ADJ(f)     (n_u && !n_na && !n_ce && (n_j & AD_B) == AD_B)
+#define FMT_ADJ(f)     (n_u && !n_ce && n_j)
 
 static int fmt_fillwords(struct fmt *f, int br);
 
@@ -194,7 +194,7 @@ static int fmt_extractline(struct fmt *f, int beg, int end, 
int str)
                return 1;
        llen = FMT_LLEN(f);
        w = fmt_wordslen(f, beg, end);
-       if (str && FMT_ADJ(f) && n_j & AD_K) {
+       if (str && FMT_ADJ(f) && n_j == AD_K) {
                fmt_keshideh(f, beg, end, llen - w);
                w = fmt_wordslen(f, beg, end);
        }
diff --git a/reg.c b/reg.c
index e817de7..00d5d53 100644
--- a/reg.c
+++ b/reg.c
@@ -33,11 +33,11 @@ static int env_id;          /* current environment id */
 static int eregs_idx[NREGS];   /* register environment index in eregs[] */
 
 static char *eregs[] = {       /* environment-specific number registers */
-       "ln", ".f", ".i", ".j", ".l",
+       "ln", ".al", ".f", ".i", ".j", ".l",
        ".L", ".nI", ".nm", ".nM", ".nn",
        ".nS", ".m", ".s", ".u", ".v",
        ".it", ".itn", ".mc", ".mcn",
-       ".ce", ".f0", ".i0", ".l0",
+       ".ce", ".al0", ".f0", ".i0", ".j0", ".l0",
        ".hy", ".hycost", ".hycost2", ".hycost3", ".hlm",
        ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss", ".pmll", ".pmllcost",
        ".ti", ".lt", ".lt0", ".v0",
@@ -229,10 +229,13 @@ static void env_set(int id)
        if (!env) {
                envs[id] = env_alloc();
                env = envs[id];
+               n_al = AL_L;
+               n_al0 = AL_L;
                n_f = 1;
                n_i = 0;
                n_I = 0;
                n_j = AD_B;
+               n_j0 = AD_B;
                n_l = SC_IN * 65 / 10;
                n_L = 1;
                n_s = 10;
@@ -240,7 +243,6 @@ static void env_set(int id)
                n_v = 12 * SC_PT;
                n_s0 = n_s;
                n_f0 = n_f;
-               n_na = 0;
                n_lt = SC_IN * 65 / 10;
                n_hy = 1;
                n_ss = 12;
diff --git a/ren.c b/ren.c
index 8a9a204..4e532ed 100644
--- a/ren.c
+++ b/ren.c
@@ -236,15 +236,15 @@ static int down(int n)
        return ren_pagelimit(0);
 }
 
-/* line adjustment */
-static int ren_ljust(struct sbuf *spre, int w, int ad, int li, int lI, int ll)
+/* line alignment */
+static int ren_ljust(struct sbuf *spre, int w, int al, int li, int lI, int ll)
 {
        int ljust = li;
        int llen = ll - lI - li;
        n_n = w;
-       if ((ad & AD_B) == AD_C)
+       if (al == AL_C)
                ljust += llen > w ? (llen - w) / 2 : 0;
-       if ((ad & AD_B) == AD_R)
+       if (al == AL_R)
                ljust += llen - w;
        if (ljust)
                sbuf_printf(spre, "%ch'%du'", c_ec, ljust);
@@ -326,7 +326,7 @@ static void ren_mc(struct sbuf *sbuf, int w, int ljust)
 }
 
 /* process a line and print it with ren_out() */
-static int ren_line(char *line, int w, int ad, int body,
+static int ren_line(char *line, int w, int al, int body,
                int li, int lI, int ll, int els_neg, int els_pos)
 {
        struct sbuf sbeg, send, sbuf;
@@ -336,7 +336,7 @@ static int ren_line(char *line, int w, int ad, int body,
        sbuf_init(&send);
        sbuf_init(&sbuf);
        sbuf_append(&sbuf, line);
-       lspc = MAX(1, n_L) * n_v;       /* line space, ignoreing \x */
+       lspc = MAX(1, n_L) * n_v;       /* line space, ignoring \x */
        prev_d = n_d;
        if (!n_ns || line[0] || els_neg || els_pos) {
                if (els_neg)
@@ -346,7 +346,7 @@ static int ren_line(char *line, int w, int ad, int body,
                        ren_lnum(&sbeg);
                if (!ren_div && dir_do)
                        ren_dir(&sbuf);
-               ljust = ren_ljust(&sbeg, w, ad, li, lI, ll);
+               ljust = ren_ljust(&sbeg, w, al, li, lI, ll);
                if (line[0] && body && n_mc)
                        ren_mc(&send, w, ljust);
                ren_out(sbuf_buf(&sbeg), sbuf_buf(&sbuf), sbuf_buf(&send));
@@ -373,18 +373,16 @@ static int ren_passline(struct fmt *fmt)
 {
        char *buf;
        int ll, li, lI, els_neg, els_pos, w, ret;
-       int ad = n_j;
+       int al = n_al;
        ren_first();
        if (!fmt_morewords(fmt))
                return 0;
        buf = fmt_nextline(fmt, &w, &li, &lI, &ll, &els_neg, &els_pos);
-       if ((n_cp && !n_u) || n_na)
-               ad = AD_L;
-       else if ((ad & AD_B) == AD_B)
-               ad = n_td > 0 ? AD_R : AD_L;
+       if (n_cp && !n_u)
+               al = AL_L;
        if (n_ce)
-               ad = AD_C;
-       ret = ren_line(buf, w, ad, 1, li, lI, ll, els_neg, els_pos);
+               al = AL_C;
+       ret = ren_line(buf, w, al, 1, li, lI, ll, els_neg, els_pos);
        free(buf);
        return ret;
 }
@@ -568,6 +566,10 @@ void tr_l2r(char **args)
        dir_do = 1;
        if (args[0][0] == c_cc)
                ren_br();
+       if (n_td) {
+               if (n_al != AL_C) n_al = AL_C - n_al;
+               if (n_al0 != AL_C) n_al0 = AL_C - n_al0;
+       }
        n_td = 0;
        n_cd = 0;
 }
@@ -577,6 +579,10 @@ void tr_r2l(char **args)
        dir_do = 1;
        if (args[0][0] == c_cc)
                ren_br();
+       if (!n_td) {
+               if (n_al != AL_C) n_al = AL_C - n_al;
+               if (n_al0 != AL_C) n_al0 = AL_C - n_al0;
+       }
        n_td = 1;
        n_cd = 1;
 }
@@ -932,7 +938,7 @@ void ren_tl(int (*next)(void), void (*back)(int))
        ren_untilmap(&wb2, next, back, delim, c_pc, pgnum);
        wb_cpy(&wb, &wb2, n_lt - wb_wid(&wb2));
        /* flushing the line */
-       ren_line(wb_buf(&wb), wb_wid(&wb), AD_L, 0,
+       ren_line(wb_buf(&wb), wb_wid(&wb), AL_L, 0,
                        0, 0, n_lt, wb.els_neg, wb.els_pos);
        wb_done(&wb2);
        wb_done(&wb);
@@ -1021,7 +1027,7 @@ void tr_popren(char **args)
        ren_level = args[1] ? atoi(args[1]) : 0;
 }
 
-#define FMT_PAR()      (n_u && !n_na && !n_ce && (n_j & AD_P) == AD_P)
+#define FMT_PAR()      (n_u && !n_ce && n_j == AD_P)
 
 /* read characters from tr.c and pass the rendered lines to out.c */
 static int render_rec(int level)
diff --git a/roff.h b/roff.h
index ac7fd62..e27df90 100644
--- a/roff.h
+++ b/roff.h
@@ -308,13 +308,16 @@ int hy_cput(char *d, char *s);
 void hyph_init(void);
 void hyph_done(void);
 
+/* alignment types */
+#define AL_L           1       /* flush left (flag) */
+#define AL_R           2       /* flush right (flag) */
+#define AL_C           3       /* center (mask) */
+
 /* adjustment types */
-#define AD_C           0       /* center */
-#define AD_L           1       /* adjust left margin (flag) */
-#define AD_R           2       /* adjust right margin (flag) */
-#define AD_B           3       /* adjust both margin (mask) */
-#define AD_P           4       /* paragraph-at-once adjustment (flag) */
-#define AD_K           8       /* keshideh adjustment (flag) */
+#define AD_0           0       /* adjustment off */
+#define AD_B           1       /* adjust separate lines (flag) */
+#define AD_P           2       /* adjust entire paragraph (flag) */
+#define AD_K           3       /* keshideh adjustment (mask) */
 
 /* line formatting */
 struct fmt *fmt_alloc(void);
@@ -458,6 +461,8 @@ int clr_get(char *s);
 
 /* builtin number registers; n_X for .X register */
 #define n_a            (*nreg(DOTMAP('a')))
+#define n_al           (*nreg(map(".al")))
+#define n_al0          (*nreg(map(".al0")))
 #define n_cp           (*nreg(DOTMAP('C')))
 #define n_d            (*nreg(DOTMAP('d')))
 #define n_f            (*nreg(DOTMAP('f')))
@@ -467,6 +472,7 @@ int clr_get(char *s);
 #define n_itn          (*nreg(map(".itn")))    /* .it lines left */
 #define n_I            (*nreg(DOTMAP('I')))    /* base indent */
 #define n_j            (*nreg(DOTMAP('j')))
+#define n_j0           (*nreg(map(".j0")))
 #define n_l            (*nreg(DOTMAP('l')))
 #define n_L            (*nreg(DOTMAP('L')))
 #define n_lsn          (*nreg(map("lsn")))     /* for .lsm */
@@ -513,7 +519,6 @@ int clr_get(char *s);
 #define n_L0           (*nreg(map(".L0")))     /* last .L */
 #define n_m0           (*nreg(map(".m0")))     /* last .m */
 #define n_mk           (*nreg(map(".mk")))     /* .mk internal register */
-#define n_na           (*nreg(map(".na")))     /* .na mode */
 #define n_ns           (*nreg(map(".ns")))     /* .ns mode */
 #define n_o0           (*nreg(map(".o0")))     /* last .o */
 #define n_pmll         (*nreg(map(".pmll")))   /* minimum line length (.pmll) 
*/
diff --git a/tr.c b/tr.c
index 7aa6b7a..b0f8ca1 100644
--- a/tr.c
+++ b/tr.c
@@ -322,39 +322,48 @@ static void tr_el(char **args)
        cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
 }
 
-static void tr_na(char **args)
-{
-       n_na = 1;
-}
-
-static int adjmode(int c, int def)
+static void tr_al(char **args)
 {
-       switch (c) {
-       case 'l':
-               return AD_L;
-       case 'r':
-               return AD_R;
-       case 'c':
-               return AD_C;
-       case 'b':
-       case 'n':
-               return AD_B;
-       case 'k':
-               return AD_B | AD_K;
-       }
-       return def;
+       char *s = args[1];
+       int al = n_al;
+       if (!s)
+               n_al = n_al0;
+       else if (*s == 'l')
+               n_al = AL_L;
+       else if (*s == 'r')
+               n_al = AL_R;
+       else if (*s == 'c')
+               n_al = AL_C;
+       else if (isdigit((unsigned char) *s))
+               n_al = MIN(1, atoi(s) & 3);
+       else
+               return;
+       n_al0 = al;
 }
 
 static void tr_ad(char **args)
 {
        char *s = args[1];
-       n_na = 0;
+       int j = n_j;
        if (!s)
-               return;
-       if (isdigit((unsigned char) s[0]))
-               n_j = atoi(s) & 15;
+               n_j = n_j0;
+       else if (*s == 'b')
+               n_j = AD_B;
+       else if (*s == 'p')
+               n_j = AD_P;
+       else if (*s == 'k')
+               n_j = AD_K;
+       else if (isdigit((unsigned char) *s))
+               n_j = atoi(s) & 3;
        else
-               n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], 
n_j);
+               return;
+       n_j0 = j;
+}
+
+static void tr_na(char **args)
+{
+       args = (char*[NARGS]){ ".na", "0" };
+       tr_ad(args);
 }
 
 static void tr_tm(char **args)
@@ -1107,6 +1116,7 @@ static struct cmd {
        {"ab", tr_ab, mkargs_eol},
        {"ad", tr_ad},
        {"af", tr_af},
+       {"al", tr_al},
        {"am", tr_de, mkargs_reg1},
        {"as", tr_as, mkargs_ds},
        {"bd", tr_bd},
-- 
2.47.1

Reply via email to