ref: 96f08d8dc0198c6c1ac478349ed76398c5cf7401
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Nov 16 07:12:09 EST 2012
neatroff skeleton
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,11 @@
+CC = cc
+CFLAGS = -Wall -O2
+LDFLAGS =
+
+all: xroff
+%.o: %.c xroff.h
+ $(CC) -c $(CFLAGS) $<
+xroff: xroff.o dev.o font.o in.o cp.o tr.o out.o reg.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+clean:
+ rm -f *.o xroff
--- /dev/null
+++ b/cp.c
@@ -1,0 +1,15 @@
+#include "xroff.h"
+
+static int cp_backed = -1;
+
+int cp_next(void)
+{
+ int ret = cp_backed >= 0 ? cp_backed : in_next();
+ cp_backed = -1;
+ return ret;
+}
+
+void cp_back(int c)
+{
+ cp_backed = c;
+}
--- /dev/null
+++ b/dev.c
@@ -1,0 +1,177 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xroff.h"
+
+#define PATHLEN 1024
+#define MAXFONTS 32
+
+char dev_dir[PATHLEN]; /* device directory */
+int dev_res; /* device resolution */
+int dev_uwid; /* device unitwidth */
+int dev_hor; /* minimum horizontal movement */
+int dev_ver; /* minimum vertical movement */
+
+/* mounted fonts */
+static char fn_name[MAXFONTS][FNLEN]; /* font names */
+static struct font *fn_font[MAXFONTS]; /* font structs */
+static int fn_n; /* number of mounted fonts */
+
+static void skipline(FILE* filp)
+{
+ int c;
+ do {
+ c = getc(filp);
+ } while (c != '\n' && c != EOF);
+}
+
+static void dev_prologue(void)
+{
+ printf("x T utf\n");
+ printf("x res %d %d %d\n", dev_res, dev_hor, dev_ver);
+ printf("x init\n");
+ printf("V0\n");
+ printf("p1\n");
+}
+
+int dev_mnt(int pos, char *id, char *name)
+{
+ char path[PATHLEN];
+ struct font *fn;
+ sprintf(path, "%s/%s", dev_dir, name);
+ fn = font_open(path);
+ if (!fn)
+ return -1;
+ if (fn_font[pos])
+ font_close(fn_font[pos]);
+ if (fn_name[pos] != name) /* ignore if fn_name[pos] is passed */
+ strcpy(fn_name[pos], name);
+ fn_font[pos] = fn;
+ printf("x font %d %s\n", pos, name);
+ return pos;
+}
+
+int dev_open(char *dir)
+{
+ char path[PATHLEN];
+ char tok[LLEN];
+ int i;
+ FILE *desc;
+ strcpy(dev_dir, dir);
+ sprintf(path, "%s/DESC", dir);
+ desc = fopen(path, "r");
+ while (fscanf(desc, "%s", tok) == 1) {
+ if (tok[0] == '#') {
+ skipline(desc);
+ continue;
+ }
+ if (!strcmp("fonts", tok)) {
+ fscanf(desc, "%d", &fn_n);
+ for (i = 0; i < fn_n; i++)
+ fscanf(desc, "%s", fn_name[i + 1]);
+ fn_n++;
+ continue;
+ }
+ if (!strcmp("sizes", tok)) {
+ while (fscanf(desc, "%s", tok) == 1)
+ if (!strcmp("0", tok))
+ break;
+ continue;
+ }
+ if (!strcmp("res", tok)) {
+ fscanf(desc, "%d", &dev_res);
+ continue;
+ }
+ if (!strcmp("unitwidth", tok)) {
+ fscanf(desc, "%d", &dev_uwid);
+ continue;
+ }
+ if (!strcmp("hor", tok)) {
+ fscanf(desc, "%d", &dev_hor);
+ continue;
+ }
+ if (!strcmp("ver", tok)) {
+ fscanf(desc, "%d", &dev_ver);
+ continue;
+ }
+ if (!strcmp("charset", tok)) {
+ break;
+ }
+ }
+ fclose(desc);
+ dev_prologue();
+ for (i = 0; i < fn_n; i++)
+ if (*fn_name[i])
+ dev_mnt(i, fn_name[i], fn_name[i]);
+ return 0;
+}
+
+static void dev_epilogue(void)
+{
+ printf("x trailer\n");
+ printf("x stop\n");
+}
+
+void dev_close(void)
+{
+ int i;
+ dev_epilogue();
+ for (i = 0; i < fn_n; i++) {
+ if (fn_font[i])
+ font_close(fn_font[i]);
+ fn_font[i] = NULL;
+ }
+}
+
+/* glyph handling functions */
+
+struct glyph *dev_glyph(char *c)
+{
+ struct glyph *g = font_find(fn_font[n_f], c);
+ int i;
+ if (g)
+ return g;
+ for (i = 0; i < fn_n; i++)
+ if (fn_font[i] && fn_font[i]->special)
+ if ((g = font_find(fn_font[i], c)))
+ return g;
+ return NULL;
+}
+
+struct glyph *dev_glyph_byid(char *id)
+{
+ return font_glyph(fn_font[n_f], id);
+}
+
+struct glyph *dev_ligature(char **s, int n)
+{
+ return NULL;
+}
+
+int dev_kernpair(char *c1, char *c2)
+{
+ return 0;
+}
+
+int dev_spacewid(void)
+{
+ return fn_font[n_f]->spacewid;
+}
+
+int dev_font(char *id)
+{
+ int i;
+ if (isdigit(id[0])) {
+ int num = atoi(id);
+ if (num < 0 || num >= fn_n || !fn_font[num]) {
+ errmsg("bad font position\n");
+ return -1;
+ }
+ return num;
+ }
+ for (i = 0; i < fn_n; i++)
+ if (!strcmp(fn_name[i], id))
+ return i;
+ return dev_mnt(0, id, id);
+}
--- /dev/null
+++ b/font.c
@@ -1,0 +1,123 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xroff.h"
+
+static void skipline(FILE* filp)
+{
+ int c;
+ do {
+ c = getc(filp);
+ } while (c != '\n' && c != EOF);
+}
+
+struct glyph *font_find(struct font *fn, char *name)
+{
+ int i;
+ for (i = 0; i < fn->n; i++)
+ if (!strcmp(name, fn->c[i]))
+ return fn->g[i];
+ return NULL;
+}
+
+struct glyph *font_glyph(struct font *fn, char *id)
+{
+ int i;
+ for (i = 0; i < fn->nglyphs; i++)
+ if (!strcmp(fn->glyphs[i].id, id))
+ return &fn->glyphs[i];
+ return NULL;
+}
+
+static struct glyph *font_glyphmk(struct font *fn, char *id)
+{
+ struct glyph *g = font_glyph(fn, id);
+ if (g)
+ return g;
+ g = &fn->glyphs[fn->nglyphs++];
+ strcpy(g->id, id);
+ return g;
+}
+
+static void font_charset(struct font *fn, FILE *fin)
+{
+ char tok[LLEN];
+ char name[LLEN];
+ char id[LLEN];
+ struct glyph *glyph = NULL;
+ struct glyph *prev = NULL;
+ int wid, type;
+ while (1) {
+ if (fscanf(fin, "%s", name) != 1)
+ break;
+ fscanf(fin, "%s", tok);
+ glyph = prev;
+ if (strcmp("\"", tok)) {
+ wid = atoi(tok);
+ fscanf(fin, "%d %s", &type, id);
+ skipline(fin);
+ glyph = font_glyphmk(fn, id);
+ strcpy(glyph->name, name);
+ glyph->wid = wid;
+ glyph->type = type;
+ glyph->font = fn;
+ }
+ prev = glyph;
+ strcpy(fn->c[fn->n], name);
+ fn->g[fn->n] = glyph;
+ fn->n++;
+ }
+}
+
+struct font *font_open(char *path)
+{
+ struct font *fn = malloc(sizeof(*fn));
+ char tok[LLEN];
+ FILE *fin;
+ fin = fopen(path, "r");
+ memset(fn, 0, sizeof(*fn));
+ while (fscanf(fin, "%s", tok) == 1) {
+ if (tok[0] == '#') {
+ skipline(fin);
+ continue;
+ }
+ if (!strcmp("spacewidth", tok)) {
+ fscanf(fin, "%d", &fn->spacewid);
+ continue;
+ }
+ if (!strcmp("special", tok)) {
+ fn->special = 1;
+ continue;
+ }
+ if (!strcmp("name", tok)) {
+ fscanf(fin, "%s", fn->name);
+ continue;
+ }
+ if (!strcmp("fontname", tok)) {
+ skipline(fin);
+ continue;
+ }
+ if (!strcmp("named", tok)) {
+ skipline(fin);
+ continue;
+ }
+ if (!strcmp("ligatures", tok)) {
+ while (fscanf(fin, "%s", tok) == 1)
+ if (!strcmp("0", tok))
+ break;
+ skipline(fin);
+ continue;
+ }
+ if (!strcmp("charset", tok)) {
+ font_charset(fn, fin);
+ break;
+ }
+ }
+ fclose(fin);
+ return fn;
+}
+
+void font_close(struct font *fn)
+{
+ free(fn);
+}
--- /dev/null
+++ b/in.c
@@ -1,0 +1,6 @@
+#include <stdio.h>
+
+int in_next(void)
+{
+ return getchar();
+}
--- /dev/null
+++ b/out.c
@@ -1,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xroff.h"
+
+static int out_blank = 0;
+
+static int utf8len(int c)
+{
+ if (c <= 0x7f)
+ return 1;
+ if (c >= 0xfc)
+ return 6;
+ if (c >= 0xf8)
+ return 5;
+ if (c >= 0xf0)
+ return 4;
+ if (c >= 0xe0)
+ return 3;
+ if (c >= 0xc0)
+ return 2;
+ return 1;
+}
+
+static int nextchar(char *s)
+{
+ int c = tr_next();
+ int l = utf8len(c);
+ int i;
+ if (c < 0)
+ return 0;
+ s[0] = c;
+ for (i = 1; i < l; i++)
+ s[i] = tr_next();
+ s[l] = '\0';
+ return l;
+}
+
+static void out_sp(int n)
+{
+ printf("H%d", n_o + n_i);
+ printf("v%d\n", n_v * (n + 1));
+ out_blank = 0;
+}
+
+void tr_br(int argc, char **args)
+{
+ out_sp(0);
+}
+
+void tr_sp(int argc, char **args)
+{
+ out_sp(argc > 1 ? atoi(args[1]) : 1);
+}
+
+void render(void)
+{
+ char c[LLEN];
+ struct glyph *g;
+ int fp = n_f;
+ int ps = n_s;
+ while (nextchar(c) > 0) {
+ g = NULL;
+ if (c[0] == '\\') {
+ nextchar(c);
+ if (c[0] == '(') {
+ int l = nextchar(c);
+ l += nextchar(c + l);
+ c[l] = '\0';
+ }
+ }
+ g = dev_glyph(c);
+ if (ps != n_s) {
+ printf("s%d\n", n_s);
+ ps = n_s;
+ }
+ if (fp != n_f) {
+ printf("f%d\n", n_f);
+ fp = n_f;
+ }
+ if (g) {
+ if (out_blank)
+ printf("h%d", dev_spacewid() * n_s / dev_uwid);
+ if (utf8len(c[0]) == strlen(c)) {
+ printf("c%s%s", c, c[1] ? "\n" : "");
+ } else {
+ printf("C%s\n", c);
+ }
+ printf("h%d", g->wid * n_s / dev_uwid);
+ out_blank = 0;
+ } else {
+ out_blank = 1;
+ }
+ }
+}
--- /dev/null
+++ b/reg.c
@@ -1,0 +1,27 @@
+#include <stdlib.h>
+#include "xroff.h"
+
+#define NREGS (1 << 16)
+
+int nreg[NREGS];
+
+int num_get(int id)
+{
+ return nreg[id];
+}
+
+int num_set(int id, int n)
+{
+ int o = nreg[id];
+ nreg[id] = n;
+ return o;
+}
+
+void tr_nr(int argc, char **args)
+{
+ int id;
+ if (argc < 3)
+ return;
+ id = N_ID(args[1][0], args[1][1]);
+ nreg[id] = atoi(args[2]);
+}
--- /dev/null
+++ b/tr.c
@@ -1,0 +1,121 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xroff.h"
+
+#define NARGS 10
+#define LINEL 1024
+#define LEN(a) (sizeof(a) / sizeof((a)[0]))
+
+static int tr_nl = 1;
+
+static void tr_ft(int argc, char **args)
+{
+ int fn;
+ if (argc < 2)
+ return;
+ fn = dev_font(args[1]);
+ if (fn >= 0)
+ n_f = fn;
+}
+
+static void tr_ps(int argc, char **args)
+{
+ if (argc >= 2)
+ n_s = atoi(args[1]);
+}
+
+static void tr_vs(int argc, char **args)
+{
+ if (argc >= 2)
+ n_v = atoi(args[1]) * SC_PT;
+}
+
+static void tr_ll(int argc, char **args)
+{
+ if (argc >= 2)
+ n_v = atoi(args[1]) * SC_PT;
+}
+
+static void tr_in(int argc, char **args)
+{
+ if (argc >= 2)
+ n_v = atoi(args[1]) * SC_PT;
+}
+
+static void tr_readcmd(char *s)
+{
+ int i = 0;
+ int c;
+ while ((c = cp_next()) == ' ')
+ ;
+ while (i < 2 && c > 0 && isprint(c)) {
+ s[i++] = c;
+ c = cp_next();
+ }
+ s[i] = '\0';
+ if (!isprint(c))
+ cp_back(c);
+}
+
+static int tr_readargs(char **args, int maxargs, char *buf, int len)
+{
+ char *s = buf;
+ char *e = buf + len - 1;
+ int c;
+ int n = 0;
+ while ((c = cp_next()) == ' ')
+ ;
+ while (n < maxargs && s < e && c > 0 && c != '\n') {
+ args[n++] = s;
+ while (s < e && c > 0 && c != ' ' && c != '\n') {
+ *s++ = c;
+ c = cp_next();
+ }
+ *s++ = '\0';
+ while (c == ' ')
+ c = cp_next();
+ }
+ if (c != '\n')
+ cp_back(c);
+ return n;
+}
+
+static struct cmd {
+ char *id;
+ void (*f)(int argc, char **args);
+} cmds[] = {
+ {"br", tr_br},
+ {"ft", tr_ft},
+ {"nr", tr_nr},
+ {"ps", tr_ps},
+ {"sp", tr_sp},
+ {"vs", tr_vs},
+ {"vs", tr_ll},
+ {"vs", tr_in},
+};
+
+int tr_next(void)
+{
+ int c = cp_next();
+ int nl = c == '\n';
+ char *args[NARGS];
+ char buf[LINEL];
+ char cmd[LINEL];
+ int argc;
+ int i;
+ while (tr_nl && (c == '.' || c == '\'')) {
+ nl = 1;
+ args[0] = cmd;
+ cmd[0] = c;
+ tr_readcmd(cmd + 1);
+ argc = tr_readargs(args + 1, NARGS - 1, buf, LINEL);
+ for (i = 0; i < LEN(cmds); i++)
+ if (!strcmp(cmd + 1, cmds[i].id))
+ cmds[i].f(argc + 1, args);
+ c = cp_next();
+ }
+ tr_nl = nl;
+ return c;
+}
--- /dev/null
+++ b/xroff.c
@@ -1,0 +1,37 @@
+#include <stdio.h>
+#include "xroff.h"
+
+static void g_init(void)
+{
+ n_f = 1;
+ n_o = SC_IN;
+ n_p = SC_IN * 11;
+ n_l = SC_IN * 65 / 10;
+ n_i = 0;
+ n_s = 10;
+ n_v = 12 * SC_PT;
+}
+
+static void compile(void)
+{
+ printf("s%d\n", n_s);
+ printf("f%d\n", n_f);
+ printf("H%d\n", n_o);
+ printf("V%d\n", n_v);
+ render();
+ printf("V%d\n", n_p);
+}
+
+void errmsg(char *msg)
+{
+ fprintf(stderr, "%s", msg);
+}
+
+int main(void)
+{
+ dev_open("/root/troff/home/font/devutf");
+ g_init();
+ compile();
+ dev_close();
+ return 0;
+}
--- /dev/null
+++ b/xroff.h
@@ -1,0 +1,81 @@
+#define SC_IN (dev_res)
+#define SC_PT (SC_IN / 72)
+
+#define FNLEN 32
+#define FNGLYPHS 512
+#define FNNAME 32
+#define LLEN 128
+
+/* number registers */
+extern int nreg[];
+int num_get(int id);
+int num_set(int id, int n);
+
+/* builtin number registers; n_X for .X register */
+#define N_ID(c1, c2) ((c1) * 256 + (c2))
+#define n_f nreg[N_ID('.', 'f')]
+#define n_s nreg[N_ID('.', 's')]
+#define n_o nreg[N_ID('.', 'o')]
+#define n_p nreg[N_ID('.', 'p')]
+#define n_l nreg[N_ID('.', 'l')]
+#define n_v nreg[N_ID('.', 'v')]
+#define n_i nreg[N_ID('.', 'i')]
+
+/* device related variables */
+extern int dev_res;
+extern int dev_uwid;
+extern int dev_hor;
+extern int dev_ver;
+
+struct glyph {
+ char name[FNNAME]; /* name of the glyph */
+ char id[FNNAME]; /* device-dependent glyph identifier */
+ struct font *font; /* glyph font */
+ int wid; /* character width */
+ int type; /* character type; ascender/descender */
+};
+
+struct font {
+ char name[FNLEN];
+ struct glyph glyphs[FNGLYPHS];
+ int nglyphs;
+ int spacewid;
+ int special;
+ char c[FNGLYPHS][FNNAME]; /* character names in charset */
+ struct glyph *g[FNGLYPHS]; /* character glyphs in charset */
+ int n; /* number of characters in charset */
+};
+
+/* output device functions */
+int dev_open(char *path);
+void dev_close(void);
+int dev_mnt(int pos, char *id, char *name);
+int dev_font(char *id);
+
+/* font-related functions */
+struct font *font_open(char *path);
+void font_close(struct font *fn);
+struct glyph *font_glyph(struct font *fn, char *id);
+struct glyph *font_find(struct font *fn, char *name);
+
+/* glyph handling functions */
+struct glyph *dev_glyph(char *c);
+struct glyph *dev_glyph_byid(char *id);
+int dev_spacewid(void);
+
+/* different layers of neatroff */
+int in_next(void);
+int cp_next(void);
+int tr_next(void);
+void cp_back(int c);
+
+/* rendering */
+void render(void);
+
+/* error messages */
+void errmsg(char *msg);
+
+/* troff commands */
+void tr_br(int argc, char **args);
+void tr_sp(int argc, char **args);
+void tr_nr(int argc, char **args);