shithub: neatroff

Download patch

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);