shithub: neatroff

Download patch

ref: ba2d79127881030e079be609d77df850b660dd2d
parent: 9358139dacada10f22281ef575e4b80435d9184b
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jul 1 13:12:22 EDT 2014

dict: use dict struct where possible

--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
 all: roff
 %.o: %.c roff.h
 	$(CC) -c $(CFLAGS) $<
-roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o fmt.o eval.o draw.o wb.o hyph.o map.o clr.o char.o
+roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o fmt.o eval.o draw.o wb.o hyph.o map.o clr.o char.o dict.o
 	$(CC) -o $@ $^ $(LDFLAGS)
 clean:
 	rm -f *.o roff
--- /dev/null
+++ b/dict.c
@@ -1,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "roff.h"
+
+#define DHASH(d, s)	((d)->level2 ? (((unsigned char) (s)[1]) << 8) | (unsigned char) (s)[0] : (unsigned char) s[0])
+
+/*
+ * initialise a dictionary
+ *
+ * notfound: the value returned for missing keys.
+ * dupkeys: if nonzero, store a copy of keys inserted via dict_put().
+ * level2: use two characters for hasing
+ */
+void dict_init(struct dict *d, int size, long notfound, int dupkeys, int level2)
+{
+	memset(d, 0, sizeof(*d));
+	d->size = size;
+	d->n = 1;
+	d->level2 = level2;
+	d->notfound = notfound;
+	d->key = malloc(size * sizeof(d->key[0]));
+	d->val = malloc(size * sizeof(d->val[0]));
+	d->next = malloc(size * sizeof(d->next[0]));
+	d->head = malloc((level2 ? 256 * 256 : 256) * sizeof(d->next[0]));
+	if (dupkeys)
+		d->buf = malloc(size * NMLEN);
+}
+
+void dict_done(struct dict *d)
+{
+	free(d->val);
+	free(d->key);
+	free(d->next);
+	free(d->buf);
+	free(d->head);
+}
+
+void dict_put(struct dict *d, char *key, long val)
+{
+	int idx;
+	if (d->n >= d->size)
+		return;
+	if (d->buf) {
+		int len = strlen(key) + 1;
+		if (d->buflen + len >= d->size * NMLEN)
+			return;
+		memcpy(d->buf + d->buflen, key, len);
+		key = d->buf + d->buflen;
+		d->buflen += len;
+	}
+	idx = d->n++;
+	d->key[idx] = key;
+	d->val[idx] = val;
+	d->next[idx] = d->head[DHASH(d, key)];
+	d->head[DHASH(d, key)] = idx;
+}
+
+/* return the index of key in d */
+int dict_idx(struct dict *d, char *key)
+{
+	int idx = d->head[DHASH(d, key)];
+	while (idx > 0) {
+		if (!strcmp(d->key[idx], key))
+			return idx;
+		idx = d->next[idx];
+	}
+	return -1;
+}
+
+char *dict_key(struct dict *d, int idx)
+{
+	return d->key[idx];
+}
+
+long dict_val(struct dict *d, int idx)
+{
+	return d->val[idx];
+}
+
+long dict_get(struct dict *d, char *key)
+{
+	int idx = dict_idx(d, key);
+	return idx >= 0 ? d->val[idx] : d->notfound;
+}
+
+/* match a prefix of key; in the first call, *idx should be -1 */
+long dict_prefix(struct dict *d, char *key, int *idx)
+{
+	int plen;
+	if (!*idx)
+		return d->notfound;
+	if (*idx < 0)
+		*idx = d->head[DHASH(d, key)];
+	else
+		*idx = d->next[*idx];
+	while (*idx > 0) {
+		plen = strlen(d->key[*idx]);
+		if (!strncmp(d->key[*idx], key, plen))
+			return d->val[*idx];
+		*idx = d->next[*idx];
+	}
+	return d->notfound;
+}
--- a/font.c
+++ b/font.c
@@ -4,35 +4,19 @@
 #include <string.h>
 #include "roff.h"
 
-/* look up a character in chead[]/cnext[] table */
-static int font_cidx(struct font *fn, char *name)
-{
-	int i = fn->chead[(unsigned char) name[0]];
-	while (i >= 0 && strcmp(name, fn->c[i]))
-		i = fn->cnext[i];
-	return i;
-}
-
-/* look up a character in ghead[]/gnext[] table */
-static int font_gidx(struct font *fn, char *id)
-{
-	int i = fn->ghead[(unsigned char) id[0]];
-	while (i >= 0 && strcmp(fn->glyphs[i].id, id))
-		i = fn->gnext[i];
-	return i;
-}
-
+/* find a glyph by its name */
 struct glyph *font_find(struct font *fn, char *name)
 {
-	int i = font_cidx(fn, name);
+	int i = dict_get(&fn->cdict, name);
 	if (i < 0)
 		return NULL;
 	return fn->g_map[i] ? fn->g_map[i] : fn->g[i];
 }
 
+/* find a glyph by its device-dependent identifier */
 struct glyph *font_glyph(struct font *fn, char *id)
 {
-	int i = font_gidx(fn, id);
+	int i = dict_get(&fn->gdict, id);
 	return i >= 0 ? &fn->glyphs[i] : NULL;
 }
 
@@ -45,8 +29,7 @@
 	strcpy(g->name, name);
 	g->type = type;
 	g->font = fn;
-	fn->gnext[i] = fn->ghead[(unsigned char) id[0]];
-	fn->ghead[(unsigned char) id[0]] = i;
+	dict_put(&fn->gdict, g->id, i);
 	return g;
 }
 
@@ -53,7 +36,7 @@
 /* map character name to the given glyph */
 int font_map(struct font *fn, char *name, struct glyph *g)
 {
-	int i = font_cidx(fn, name);
+	int i = dict_get(&fn->cdict, name);
 	if (g && g->font != fn)
 		return 1;
 	if (i < 0) {
@@ -61,8 +44,7 @@
 			return 1;
 		i = fn->n++;
 		strcpy(fn->c[i], name);
-		fn->cnext[i] = fn->chead[(unsigned char) name[0]];
-		fn->chead[(unsigned char) name[0]] = i;
+		dict_put(&fn->cdict, fn->c[i], i);
 	}
 	fn->g_map[i] = g;
 	return 0;
@@ -71,7 +53,7 @@
 /* return nonzero if character name has been mapped with font_map() */
 int font_mapped(struct font *fn, char *name)
 {
-	int i = font_cidx(fn, name);
+	int i = dict_get(&fn->cdict, name);
 	return i >= 0 && fn->g_map[i];
 }
 
@@ -164,8 +146,7 @@
 	}
 	strcpy(fn->c[fn->n], name);
 	fn->g[fn->n] = glyph;
-	fn->cnext[fn->n] = fn->chead[(unsigned char) name[0]];
-	fn->chead[(unsigned char) name[0]] = fn->n;
+	dict_put(&fn->cdict, fn->c[fn->n], fn->n);
 	fn->n++;
 	return 0;
 }
@@ -211,10 +192,8 @@
 		return NULL;
 	}
 	memset(fn, 0, sizeof(*fn));
-	for (i = 0; i < LEN(fn->ghead); i++)
-		fn->ghead[i] = -1;
-	for (i = 0; i < LEN(fn->chead); i++)
-		fn->chead[i] = -1;
+	dict_init(&fn->gdict, NGLYPHS, -1, 0, 0);
+	dict_init(&fn->cdict, NGLYPHS, -1, 0, 0);
 	for (i = 0; i < LEN(fn->knhead); i++)
 		fn->knhead[i] = -1;
 	while (fscanf(fin, "%s", tok) == 1) {
--- a/hyph.c
+++ b/hyph.c
@@ -12,12 +12,10 @@
 static char hwword[HYPATLEN];	/* buffer for .hw words */
 static char hwhyph[HYPATLEN];	/* buffer for .hw hyphenations */
 static int hwword_len;		/* used hwword[] length */
-/* word lists (per starting characters) for dictionary entries */
-static int hwhead[256];		/* the head of hw_*[] lists */
-static int hwnext[NHYPHS];	/* the next word with the same initial */
-static int hwidx[NHYPHS];	/* the offset of this word in hwword[] */
+static struct dict hwdict;	/* map words to their index in hwoff[] */
+static int hwoff[NHYPHS];	/* the offset of this word in hwword[] */
 static int hwlen[NHYPHS];	/* the length of the word */
-static int hw_n = 1;		/* number of words in hw_*[] lists */
+static int hw_n;		/* number of words in hw_*[] lists */
 
 /* functions for the hyphenation dictionary */
 
@@ -26,7 +24,7 @@
 	char *s = word;
 	char *d = hwword + hwword_len;
 	int c, i;
-	if (hw_n == LEN(hwidx) || hwword_len + 128 > sizeof(hwword))
+	if (hw_n == LEN(hwoff) || hwword_len + 128 > sizeof(hwword))
 		return;
 	i = hw_n++;
 	while ((c = *s++)) {
@@ -36,11 +34,10 @@
 			*d++ = c;
 	}
 	*d++ = '\0';
-	hwidx[i] = hwword_len;
+	hwoff[i] = hwword_len;
 	hwword_len = d - hwword;
-	hwlen[i] = hwword_len - hwidx[i] - 1;
-	hwnext[i] = hwhead[(unsigned char) word[0]];
-	hwhead[(unsigned char) word[0]] = i;
+	hwlen[i] = hwword_len - hwoff[i] - 1;
+	dict_put(&hwdict, hwword + hwoff[i], i);
 }
 
 /* copy lower-cased s to d */
@@ -58,16 +55,10 @@
 static char *hw_lookup(char *s)
 {
 	char word[ILNLEN];
-	int i;
+	int i, idx = -1;
 	hw_strcpy(word, s);
-	/* finding a dictionary entry that matches a prefix of the input */
-	i = hwhead[(unsigned char) word[0]];
-	while (i > 0) {
-		if (!strncmp(word, hwword + hwidx[i], hwlen[i]))
-			return hwhyph + hwidx[i];
-		i = hwnext[i];
-	}
-	return NULL;
+	i = dict_prefix(&hwdict, s, &idx);
+	return i >= 0 ? hwhyph + hwoff[i] : NULL;
 }
 
 void tr_hw(char **args)
@@ -83,21 +74,10 @@
 static char hypats[HYPATLEN];	/* the patterns */
 static char hynums[HYPATLEN];	/* numbers in the patterns */
 static int hypats_len;
-/* lists (one per pair of starting characters) for storing patterns */
-static int hyhead[256 * 256];	/* the head of hy_*[] lists */
-static int hynext[NHYPHS];	/* the next pattern with the same initial */
+static struct dict hydict;	/* map patterns to their index in hyoff[] */
 static int hyoff[NHYPHS];	/* the offset of this pattern in hypats[] */
-static int hy_n = 1;		/* number of words in hy_*[] lists */
+static int hy_n;		/* number of words in hy_*[] lists */
 
-#define HYC_MAP(c)	((c) == '.' ? 0 : (c))
-
-/* index of the string starting with a and b in hyhash[] */
-static int hy_idx(char *s)
-{
-	return (HYC_MAP((unsigned char) s[1]) << 8) |
-		HYC_MAP((unsigned char) s[0]);
-}
-
 /* make s lower-case and replace its non-alphabetic characters with . */
 static void hy_strcpy(char *d, char *s)
 {
@@ -114,17 +94,15 @@
 {
 	int plen;
 	char *p, *np;
-	int j;
-	int idx = hyhead[hy_idx(s)];
-	while (idx > 0) {
-		p = hypats + hyoff[idx];
+	int i, j;
+	int idx = -1;
+	while ((i = dict_prefix(&hydict, s, &idx)) >= 0) {
+		p = hypats + hyoff[i];
 		np = hynums + (p - hypats);
 		plen = strlen(p);
-		if (!strncmp(s + 2, p + 2, plen - 2))
-			for (j = 0; j < plen; j++)
-				if (n[j] < np[j])
-					n[j] = np[j];
-		idx = hynext[idx];
+		for (j = 0; j < plen; j++)
+			if (n[j] < np[j])
+				n[j] = np[j];
 	}
 }
 
@@ -166,8 +144,7 @@
 	}
 	p[i] = '\0';
 	hyoff[idx] = hypats_len;
-	hynext[idx] = hyhead[hy_idx(p)];
-	hyhead[hy_idx(p)] = idx;
+	dict_put(&hydict, hypats + hyoff[idx], idx);
 	hypats_len += i + 1;
 }
 
@@ -237,18 +214,23 @@
 	}
 }
 
+void hyph_init(void)
+{
+	dict_init(&hwdict, NHYPHS, -1, 0, 1);
+	dict_init(&hydict, NHYPHS, -1, 0, 1);
+}
+
 void tr_hpf(char **args)
 {
 	/* reseting the patterns */
 	hypats_len = 0;
-	hy_n = 1;
-	memset(hyhead, 0, sizeof(hyhead));
-	memset(hynext, 0, sizeof(hynext));
+	hy_n = 0;
+	dict_done(&hydict);
 	/* reseting the dictionary */
 	hwword_len = 0;
-	hw_n = 1;
-	memset(hwhead, 0, sizeof(hwhead));
-	memset(hwnext, 0, sizeof(hwnext));
+	hw_n = 0;
+	dict_done(&hwdict);
 	/* reading */
+	hyph_init();
 	tr_hpfa(args);
 }
--- a/map.c
+++ b/map.c
@@ -6,39 +6,25 @@
 #define MAPBEG		256	/* the entries reserved for .x names */
 
 /* register, macro, or environments names */
-static char keys[NREGS][GNLEN];
-static int nkeys = 1;
-/* per starting character name lists */
-static int key_head[256];
-static int key_next[NREGS];
+static struct dict mapdict;
+static int mapinit;
 
-/* return the index of s in keys[]; insert it if not in keys[] */
-static int key_get(char *s)
-{
-	int head = (unsigned char) s[0];
-	int i = key_head[head];
-	if (*s == '\0')
-		return 0;
-	while (i > 0) {
-		if (keys[i][1] == s[1] && !strcmp(keys[i], s))
-			return i;
-		i = key_next[i];
-	}
-	if (nkeys >= NREGS - MAPBEG)
-		errdie("neatroff: out of register names (NREGS)\n");
-	i = nkeys++;
-	strcpy(keys[i], s);
-	key_next[i] = key_head[head];
-	key_head[head] = i;
-	return i;
-}
-
 /* map register names to [0..NREGS] */
 int map(char *s)
 {
+	int i;
 	if (s[0] == '.' && s[1] && !s[2])	/* ".x" is mapped to 'x' */
 		return (unsigned char) s[1];
-	return MAPBEG + key_get(s);
+	if (!mapinit) {
+		dict_init(&mapdict, NREGS, -1, 1, 1);
+		mapinit = 1;
+	}
+	i = dict_idx(&mapdict, s);
+	if (i < 0) {
+		dict_put(&mapdict, s, 0);
+		i = dict_idx(&mapdict, s);
+	}
+	return MAPBEG + i;
 }
 
 /* return the name mapped to id; returns a static buffer */
@@ -46,7 +32,7 @@
 {
 	static char map_buf[NMLEN];
 	if (id >= MAPBEG)
-		return keys[id - MAPBEG];
+		return dict_key(&mapdict, id - MAPBEG);
 	map_buf[0] = '.';
 	map_buf[1] = id;
 	map_buf[2] = '\0';
--- a/roff.c
+++ b/roff.c
@@ -71,6 +71,7 @@
 		fprintf(stderr, "neatroff: cannot open device %s\n", dev);
 		return 1;
 	}
+	hyph_init();
 	env_init();
 	tr_init();
 	if (i == argc)
--- a/roff.h
+++ b/roff.h
@@ -14,6 +14,7 @@
  * + eval_xyz: integer expression evaluation (eval.c)
  * + font_xyz: fonts (font.c)
  * + sbuf_xyz: variable length string buffers (sbuf.c)
+ * + dict_xyz: dictionaries (dict.c)
  * + wb_xyz: word buffers (wb.c)
  * + fmt_xyz: line formatting buffers (fmt.c)
  * + n_xyz: builtin number register xyz
@@ -111,6 +112,30 @@
 int tab_next(int pos);
 int tab_type(int pos);
 
+/* dictionary */
+struct dict {
+	int *head;
+	char **key;
+	long *val;
+	int *next;
+	int size;
+	int n;
+	char *buf;		/* buffer for keys */
+	int buflen;
+	int level2;		/* use two characters for hashing */
+	long notfound;		/* the value returned for missing keys */
+};
+
+void dict_init(struct dict *d, int size, long notfound, int dupkeys, int level2);
+void dict_done(struct dict *d);
+void dict_put(struct dict *d, char *key, long val);
+long dict_get(struct dict *d, char *key);
+long dict_pop(struct dict *d, char *key);
+int dict_idx(struct dict *d, char *key);
+char *dict_key(struct dict *d, int idx);
+long dict_val(struct dict *d, int idx);
+long dict_prefix(struct dict *d, char *key, int *idx);
+
 /* device related variables */
 extern int dev_res;
 extern int dev_uwid;
@@ -134,17 +159,13 @@
 	int spacewid;
 	int special;
 	int cs, bd;			/* for .cs and .bd requests */
+	struct dict gdict;		/* mapping from glyphs[i].id to i */
 	/* charset section characters */
 	char c[NGLYPHS][GNLEN];		/* character names in charset */
 	struct glyph *g[NGLYPHS];	/* character glyphs in charset */
 	struct glyph *g_map[NGLYPHS];	/* character remapped via font_map() */
 	int n;				/* number of characters in charset */
-	/* glyph table based on the first character of their id fields in glyphs[] */
-	int ghead[256];			/* glyph list heads */
-	int gnext[NGLYPHS];		/* next item in glyph lists */
-	/* character table based on the first character of glyph names in c[] */
-	int chead[256];			/* character list heads */
-	int cnext[NGLYPHS];		/* next item in character lists */
+	struct dict cdict;		/* mapping from c[i] to i */
 	/* font ligatures (lg*) */
 	char lg[NLIGS][LIGLEN * GNLEN];	/* ligatures */
 	int lgn;			/* number of ligatures in lg[] */
@@ -299,6 +320,7 @@
 #define HY_FIRST2	0x08	/* do not hyphenate the first two characters */
 
 void hyphenate(char *hyphs, char *word, int flg);
+void hyph_init(void);
 
 /* adjustment types */
 #define AD_C		0	/* center */
--- a/tr.c
+++ b/tr.c
@@ -547,33 +547,26 @@
 }
 
 /* character translation (.tr) */
+static struct dict cmap;		/* character mapping */
 static char cmap_src[NCMAPS][GNLEN];	/* source character */
 static char cmap_dst[NCMAPS][GNLEN];	/* character mapping */
 static int cmap_n;			/* number of translated character */
 
-static int tr_find(char *c)
-{
-	int i;
-	for (i = 0; i < cmap_n; i++)
-		if (!strcmp(c, cmap_src[i]))
-			return i;
-	return -1;
-}
-
 void cmap_add(char *c1, char *c2)
 {
-	int i = tr_find(c1);
+	int i = dict_get(&cmap, c1);
 	if (i < 0 && cmap_n < NCMAPS)
 		i = cmap_n++;
 	if (i >= 0) {
 		strcpy(cmap_src[i], c1);
 		strcpy(cmap_dst[i], c2);
+		dict_put(&cmap, cmap_src[i], i);
 	}
 }
 
 char *cmap_map(char *c)
 {
-	int i = tr_find(c);
+	int i = dict_get(&cmap, c);
 	return i >= 0 ? cmap_dst[i] : c;
 }
 
@@ -599,7 +592,7 @@
 {
 	int i;
 	for (i = 0; i < cdef_n; i++)
-		if (!strcmp(cdef_src[i], c) && (!cdef_fn[i] || cdef_fn[i] == fn))
+		if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
 			return i;
 	return -1;
 }
@@ -995,4 +988,5 @@
 	int i;
 	for (i = 0; i < LEN(cmds); i++)
 		str_dset(map(cmds[i].id), &cmds[i]);
+	dict_init(&cmap, NCMAPS, -1, 0, 0);
 }