shithub: neatroff

ref: b66f7af07003a601e2e125e2c2926586c8664571
dir: neatroff/roff.h

View raw version
/*
 * Most functions and variables in neatroff are prefixed with tokens
 * that indicate their purpose, such as:
 *
 * + tr_xyz: the implementation of troff request .xyz (mostly tr.c)
 * + in_xyz: input layer (in.c)
 * + cp_xyz: copy-mode interpretation layer (cp.c)
 * + ren_xyz: rendering characters into lines (ren.c)
 * + out_xyz: output layer for generating troff output (out.c)
 * + dev_xyz: output devices (dev.c)
 * + num_xyz: number registers (reg.c)
 * + str_xyz: string registers (reg.c)
 * + env_xyz: environments (reg.c)
 * + 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
 * + c_xyz: characters for requests like hc and mc
 *
 */

/* predefined array limits */
#define PATHLEN		1024	/* path length */
#define NFILES		16	/* number of input files */
#define NFONTS		32	/* number of fonts */
#define FNLEN		32	/* font name length */
#define GNLEN		32	/* glyph name length */
#define GNFMT		"%31s"	/* glyph name scanf format */
#define NMLEN		128	/* macro/register/environment name length */
#define RNLEN		NMLEN	/* register/macro name */
#define NREGS		8192	/* number of mapped names */
#define NARGS		32	/* number of macro arguments */
#define NPREV		16	/* environment stack depth */
#define NTRAPS		1024	/* number of traps per page */
#define NIES		128	/* number of nested .ie commands */
#define NTABS		32	/* number of tab stops */
#define NCMAPS		512	/* number of character translations (.tr) */
#define NSSTR		32	/* number of nested sstr_push() calls */
#define NFIELDS		32	/* number of fields */
#define NCHARS		32	/* number of characters for .eos, .hydash, .hystop */
#define MAXFRAC		100000	/* maximum value of the fractional part */
#define NCDEFS		128	/* number of character definitions (.char) */
#define NHYPHS		16384	/* hyphenation dictionary/patterns (.hw) */
#define NHYPHSWORD	32	/* number of hyphenations per word */
#define NHCODES		512	/* number of .hcode characters */
#define WORDLEN		256	/* word length (for hyph.c) */
#define NFEATS		128	/* number of features per font */
#define NSCRPS		64	/* number of scripts per font */
#define NLANGS		64	/* number of languages per font */

/* converting scales */
#define SC_IN		(dev_res)	/* inch in units */
#define SC_PT		(SC_IN / 72)	/* point in units */
#define SC_EM		(n_s * SC_IN / 72)

/* escape sequences */
#define ESC_Q	"bCDhHjlLNoRSvwxXZ?"	/* \X'ccc' quoted escape sequences */
#define ESC_P	"*fgkmns"		/* \Xc \X(cc \X[ccc] escape sequences */

#define MIN(a, b)	((a) < (b) ? (a) : (b))
#define MAX(a, b)	((a) < (b) ? (b) : (a))
#define LEN(a)		(sizeof(a) / sizeof((a)[0]))

/* special characters */
extern int c_ec;	/* escape character (\) */
extern int c_cc;	/* basic control character (.) */
extern int c_c2;	/* no-break control character (') */
extern char c_pc[];	/* page number character (%) */
#define c_ni	4	/* non-interpreted copy-mode escape */
#define c_hc	env_hc()/* hyphenation character */
#define c_mc	env_mc()/* margin character (.mc) */
#define c_tc	env_tc()
#define c_lc	env_lc()
#define c_bp	"\\:"	/* zero-width word break point */
#define c_nb	"\\~"	/* stretchable no-break space */

/* number registers */
#define num_get(id)	(*nreg(id))
void num_set(int id, int val);
void num_inc(int id, int pos);
void num_del(int id);
char *num_str(int id);
char *num_getfmt(int id);
void num_setfmt(int id, char *fmt);
void num_setinc(int id, int val);
int *nreg(int id);
int eval(char *s, int unit);
int eval_up(char **s, int unit);
int eval_re(char *s, int orig, int unit);

/* string registers */
void str_set(int id, char *s);
void str_dset(int id, void *d);
char *str_get(int id);
void *str_dget(int id);
void str_rm(int id);
void str_rn(int src, int dst);

/* saving and restoring registers before and after printing diverted lines */
void odiv_beg(void);
void odiv_end(void);

/* enviroments */
void env_init(void);
void env_done(void);
struct fmt *env_fmt(void);
struct wb *env_wb(void);
char *env_hc(void);
char *env_mc(void);
char *env_tc(void);
char *env_lc(void);
int tab_next(int pos);
int tab_type(int pos);

/* mapping integers to sets */
struct iset *iset_make(void);
void iset_free(struct iset *iset);
int *iset_get(struct iset *iset, int key);
void iset_put(struct iset *iset, int key, int ent);
int iset_len(struct iset *iset, int key);
int iset_has(struct iset *iset, int key, int ent);

/* mapping strings to longs */
struct dict *dict_make(int notfound, int dupkeys, int hashlen);
void dict_free(struct dict *d);
void dict_put(struct dict *d, char *key, int val);
int dict_get(struct dict *d, char *key);
int dict_idx(struct dict *d, char *key);
char *dict_key(struct dict *d, int idx);
int dict_val(struct dict *d, int idx);
int dict_prefix(struct dict *d, char *key, int *idx);

/* device related variables */
extern int dev_res;
extern int dev_uwid;
extern int dev_hor;
extern int dev_ver;

struct glyph {
	char id[GNLEN];		/* device-dependent glyph identifier */
	char name[GNLEN];	/* the first character mapped to this glyph */
	struct font *font;	/* glyph font */
	short wid;		/* character width */
	short llx, lly, urx, ury;	/* character bounding box */
	short type;		/* character type; ascender/descender */
};

/* output device functions */
int dev_open(char *dir, char *dev);
void dev_close(void);
int dev_mnt(int pos, char *id, char *name);
int dev_pos(char *id);
struct font *dev_font(int pos);
int dev_fontpos(struct font *fn);
struct glyph *dev_glyph(char *c, int fn);

/* 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);
int font_map(struct font *fn, char *name, char *id);
int font_mapped(struct font *fn, char *name);
int font_special(struct font *fn);
int font_wid(struct font *fn, int sz, int w);
int font_gwid(struct font *fn, struct font *cfn, int sz, int w);
int font_swid(struct font *fn, int sz, int ss);
void font_setcs(struct font *fn, int cs, int ps);
int font_getcs(struct font *fn);
void font_setbd(struct font *fn, int bd);
int font_getbd(struct font *fn);
void font_track(struct font *fn, int s1, int n1, int s2, int n2);
void font_setzoom(struct font *fn, int zoom);
int font_zoom(struct font *fn, int sz);
int font_feat(struct font *fn, char *name, int val);
void font_scrp(struct font *fn, char *name);
void font_lang(struct font *fn, char *name);
int font_layout(struct font *fn, struct glyph **src, int nsrc, int sz,
		struct glyph **dst, int *dmap,
		int *x, int *y, int *xadv, int *yadv, int lg, int kn);

/* different layers of neatroff */
int in_next(void);		/* input layer */
int cp_next(void);		/* copy-mode layer */
int tr_next(void);		/* troff layer */

void in_push(char *s, char **args);
void in_so(char *path);		/* .so request */
void in_nx(char *path);		/* .nx request */
void in_ex(void);		/* .ex request */
void in_lf(char *path, int ln);	/* .lf request */
void in_queue(char *path);	/* queue the given input file */
char *in_arg(int i);		/* look up argument */
int in_nargs(void);		/* number of arguments */
void in_shift(void);		/* shift the arguments */
void in_back(int c);		/* push back input character */
int in_top(void);		/* the first pushed-back character */
char *in_filename(void);	/* current filename */
int in_lnum(void);		/* current line number */

void cp_blk(int skip);		/* skip or read the next line or block */
void cp_reqbeg(void);		/* beginning of a request line */
void cp_copymode(int mode);	/* do not interpret \w and \E */
#define cp_back		in_back	/* cp.c is stateless */
int tr_nextreq(void);		/* read the next troff request */
void tr_req(int reg, char **args);	/* execute a built-in troff request */

/* variable length string buffer */
struct sbuf {
	char *s;		/* allocated buffer */
	int sz;			/* buffer size */
	int n;			/* length of the string stored in s */
};

void sbuf_init(struct sbuf *sbuf);
void sbuf_done(struct sbuf *sbuf);
char *sbuf_out(struct sbuf *sbuf);
char *sbuf_buf(struct sbuf *sbuf);
void sbuf_add(struct sbuf *sbuf, int c);
void sbuf_append(struct sbuf *sbuf, char *s);
void sbuf_printf(struct sbuf *sbuf, char *s, ...);
void sbuf_cut(struct sbuf *sbuf, int n);
int sbuf_len(struct sbuf *sbuf);
int sbuf_empty(struct sbuf *sbuf);

/* word buffer */
struct wb {
	struct sbuf sbuf;
	int f, s, m, cd;	/* the last output font and size */
	int r_f, r_s, r_m, r_cd;/* current font and size; use n_f and n_s if -1 */
	int part;		/* partial input (\c) */
	int cost;		/* the extra cost of line break after this word */
	int els_neg, els_pos;	/* extra line spacing */
	int h, v;		/* buffer vertical and horizontal positions */
	int ct, sb, st;		/* \w registers */
	int llx, lly, urx, ury;	/* bounding box */
	int icleft;		/* pending left italic correction */
	/* queued subword */
	char sub_c[WORDLEN][GNLEN];	/* the collected subword */
	int sub_n;		/* collected subword length */
	int sub_collect;	/* enable subword collection */
};

void wb_init(struct wb *wb);
void wb_done(struct wb *wb);
void wb_hmov(struct wb *wb, int n);
void wb_vmov(struct wb *wb, int n);
void wb_els(struct wb *wb, int els);
void wb_etc(struct wb *wb, char *x);
void wb_put(struct wb *wb, char *c);
void wb_putraw(struct wb *wb, char *c);
void wb_putexpand(struct wb *wb, char *c);
int wb_part(struct wb *wb);
void wb_setpart(struct wb *wb);
int wb_cost(struct wb *wb);
void wb_setcost(struct wb *wb, int cost);
void wb_drawl(struct wb *wb, int c, int h, int v);
void wb_drawc(struct wb *wb, int c, int r);
void wb_drawe(struct wb *wb, int c, int h, int v);
void wb_drawa(struct wb *wb, int c, int h1, int v1, int h2, int v2);
void wb_drawxbeg(struct wb *wb, int c);
void wb_drawxdot(struct wb *wb, int h, int v);
void wb_drawxcmd(struct wb *wb, char *cmd);
void wb_drawxend(struct wb *wb);
void wb_italiccorrection(struct wb *wb);
void wb_italiccorrectionleft(struct wb *wb);
void wb_cat(struct wb *wb, struct wb *src);
void wb_catstr(struct wb *wb, char *beg, char *end);
int wb_wid(struct wb *wb);
int wb_hpos(struct wb *wb);
int wb_vpos(struct wb *wb);
int wb_empty(struct wb *wb);
int wb_eos(struct wb *wb);
void wb_wconf(struct wb *wb, int *ct, int *st, int *sb,
		int *llx, int *lly, int *urx, int *ury);
void wb_reset(struct wb *wb);
char *wb_buf(struct wb *wb);
void wb_fnszget(struct wb *wb, int *fn, int *sz, int *m, int *cd);
void wb_fnszset(struct wb *wb, int fn, int sz, int m, int cd);
void wb_flushdir(struct wb *wb);
void wb_reset(struct wb *wb);
int wb_keshideh(char *word, struct wb *dst, int wid);
int wb_hywid(struct wb *wb);
int wb_swid(struct wb *wb);
int c_eossent(char *s);
int c_eostran(char *s);
int c_hydash(char *s);
int c_hystop(char *s);
int c_hymark(char *s);

/* character translation (.tr) */
void cmap_add(char *c1, char *c2);
char *cmap_map(char *c);
/* character definition (.char) */
char *cdef_map(char *c, int fn);
int cdef_expand(struct wb *wb, char *c, int fn);

/* hyphenation flags */
#define HY_LAST		0x02	/* do not hyphenate last lines */
#define HY_FINAL2	0x04	/* do not hyphenate the final two characters */
#define HY_FIRST2	0x08	/* do not hyphenate the first two characters */

void hyphenate(char *hyphs, char *word, int flg);
int hy_cput(char *d, char *s);
void hyph_init(void);
void hyph_done(void);

/* 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) */

/* line formatting */
struct fmt *fmt_alloc(void);
void fmt_free(struct fmt *fmt);
int fmt_wid(struct fmt *fmt);
void fmt_space(struct fmt *fmt);
void fmt_suppressnl(struct fmt *fmt);
int fmt_word(struct fmt *fmt, struct wb *wb);
int fmt_newline(struct fmt *fmt);
int fmt_fillreq(struct fmt *f);
int fmt_fill(struct fmt *fmt, int br);
int fmt_morelines(struct fmt *fmt);
int fmt_morewords(struct fmt *fmt);
char *fmt_nextline(struct fmt *fmt, int *w,
		int *li, int *lI, int *ll, int *els_neg, int *els_pos);

/* rendering */
int render(void);				/* the main loop */
int ren_parse(struct wb *wb, char *c);
int ren_char(struct wb *wb, int (*next)(void), void (*back)(int));
int ren_wid(int (*next)(void), void (*back)(int));
void ren_tl(int (*next)(void), void (*back)(int));
void ren_hline(struct wb *wb, int l, char *c);	/* horizontal line */
void ren_hlcmd(struct wb *wb, char *arg);	/* \l */
void ren_vlcmd(struct wb *wb, char *arg);	/* \L */
void ren_bcmd(struct wb *wb, char *arg);	/* \b */
void ren_ocmd(struct wb *wb, char *arg);	/* \o */
void ren_dcmd(struct wb *wb, char *arg);	/* \D */
void ren_zcmd(struct wb *wb, char *arg);	/* \Z */

/* out.c */
void out_line(char *s);				/* output rendered line */
void out_x(char *s);				/* output \X requests */
void out(char *s, ...);				/* output troff cmd */

/* troff commands */
void tr_ab(char **args);
void tr_bp(char **args);
void tr_br(char **args);
void tr_ce(char **args);
void tr_ch(char **args);
void tr_cl(char **args);
void tr_di(char **args);
void tr_divbeg(char **args);
void tr_divend(char **args);
void tr_divvs(char **args);
void tr_dt(char **args);
void tr_em(char **args);
void tr_ev(char **args);
void tr_fc(char **args);
void tr_fi(char **args);
void tr_fp(char **args);
void tr_fspecial(char **args);
void tr_ft(char **args);
void tr_hcode(char **args);
void tr_hpf(char **args);
void tr_hpfa(char **args);
void tr_hw(char **args);
void tr_in(char **args);
void tr_ll(char **args);
void tr_mk(char **args);
void tr_ne(char **args);
void tr_nf(char **args);
void tr_ns(char **args);
void tr_os(char **args);
void tr_pn(char **args);
void tr_ps(char **args);
void tr_rs(char **args);
void tr_rt(char **args);
void tr_sp(char **args);
void tr_sv(char **args);
void tr_ta(char **args);
void tr_ti(char **args);
void tr_wh(char **args);
void tr_popren(char **args);
void tr_transparent(char **args);

void tr_in2(char **args);
void tr_ti2(char **args);
void tr_l2r(char **args);
void tr_r2l(char **args);

void tr_init(void);
void tr_done(void);

char *tr_args(char **args, int brk, int (*next)(void), void (*back)(int));

/* helpers */
void errmsg(char *msg, ...);
void errdie(char *msg);
void *xmalloc(long len);
void *mextend(void *old, long oldsz, long newsz, int memsz);
/* utf-8 parsing */
int utf8len(int c);
int utf8next(char *s, int (*next)(void));
int utf8read(char **s, char *d);
int utf8one(char *s);
/* reading escapes and characters */
int charnext(char *c, int (*next)(void), void (*back)(int));
int charread(char **s, char *c);
int charnext_delim(char *c, int (*next)(void), void (*back)(int), char *delim);
int charread_delim(char **s, char *c, char *delim);
void charnext_str(char *d, char *c);
char *quotednext(int (*next)(void), void (*back)(int));
char *unquotednext(int cmd, int (*next)(void), void (*back)(int));
int escread(char **s, char **d);
/* string streams; nested next()/back() interface for string buffers */
void sstr_push(char *s);
char *sstr_pop(void);
int sstr_next(void);
void sstr_back(int c);

/* internal commands */
#define TR_DIVBEG	"\07<"	/* diversion begins */
#define TR_DIVEND	"\07>"	/* diversion ends */
#define TR_DIVVS	"\07V"	/* the amount of \n(.v inside diversions */
#define TR_POPREN	"\07P"	/* exit render_rec() */

/* mapping register, macro and environment names to indices */
#define DOTMAP(c2)	(c2)	/* optimized mapping for ".x" names */

int map(char *s);		/* map name s to an index */
char *map_name(int id);		/* return the name mapped to id */
void map_done(void);

/* text direction */
extern int dir_do;

void dir_fix(struct sbuf *sbuf, char *s);
void dir_done(void);

/* colors */
#define CLR_R(c)		(((c) >> 16) & 0xff)
#define CLR_G(c)		(((c) >> 8) & 0xff)
#define CLR_B(c)		((c) & 0xff)
#define CLR_RGB(r, g, b)	(((r) << 16) | ((g) << 8) | (b))

char *clr_str(int c);
int clr_get(char *s);

/* builtin number registers; n_X for .X register */
#define n_a		(*nreg(DOTMAP('a')))
#define n_cp		(*nreg(DOTMAP('C')))
#define n_d		(*nreg(DOTMAP('d')))
#define n_f		(*nreg(DOTMAP('f')))
#define n_h		(*nreg(DOTMAP('h')))
#define n_i		(*nreg(DOTMAP('i')))
#define n_it		(*nreg(map(".it")))	/* .it trap macro */
#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_l		(*nreg(DOTMAP('l')))
#define n_L		(*nreg(DOTMAP('L')))
#define n_lsn		(*nreg(map("lsn")))	/* for .lsm */
#define n_n		(*nreg(DOTMAP('n')))
#define n_nI		(*nreg(map(".nI")))	/* i for .nm */
#define n_nm		(*nreg(map(".nm")))	/* .nm enabled */
#define n_nM		(*nreg(map(".nM")))	/* m for .nm */
#define n_nn		(*nreg(map(".nn")))	/* remaining .nn */
#define n_nS		(*nreg(map(".nS")))	/* s for .nm */
#define n_m		(*nreg(DOTMAP('m')))
#define n_mc		(*nreg(map(".mc")))	/* .mc enabled */
#define n_mcn		(*nreg(map(".mcn")))	/* .mc distance */
#define n_o		(*nreg(DOTMAP('o')))
#define n_p		(*nreg(DOTMAP('p')))
#define n_s		(*nreg(DOTMAP('s')))
#define n_u		(*nreg(DOTMAP('u')))
#define n_v		(*nreg(DOTMAP('v')))
#define n_ct		(*nreg(map("ct")))
#define n_td		(*nreg(map(".td")))	/* text direction */
#define n_cd		(*nreg(map(".cd")))	/* current direction */
#define n_dl		(*nreg(map("dl")))
#define n_dn		(*nreg(map("dn")))
#define n_ln		(*nreg(map("ln")))
#define n_nl		(*nreg(map("nl")))
#define n_sb		(*nreg(map("sb")))
#define n_st		(*nreg(map("st")))
#define n_pg		(*nreg(map("%")))	/* % */
#define n_PG		(*nreg(DOTMAP('%')))	/* number of ejected pages */
#define n_lb		(*nreg(map(".b0")))	/* input line beg */
#define n_ce		(*nreg(map(".ce")))	/* .ce remaining */
#define n_f0		(*nreg(map(".f0")))	/* last .f */
#define n_lg		(*nreg(map(".lg")))	/* .lg mode */
#define n_hy		(*nreg(map(".hy")))	/* .hy mode */
#define n_hycost	(*nreg(map(".hycost")))	/* hyphenation cost */
#define n_hycost2	(*nreg(map(".hycost2")))	/* hyphenation cost #2 */
#define n_hycost3	(*nreg(map(".hycost3")))	/* hyphenation cost #3 */
#define n_hlm		(*nreg(map(".hlm")))	/* .hlm */
#define n_i0		(*nreg(map(".i0")))	/* last .i */
#define n_ti		(*nreg(map(".ti")))	/* pending .ti */
#define n_kn		(*nreg(map(".kn")))	/* .kn mode */
#define n_tI		(*nreg(map(".tI")))	/* pending .ti2 */
#define n_I0		(*nreg(map(".I0")))	/* last .I */
#define n_l0		(*nreg(map(".l0")))	/* last .l */
#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) */
#define n_pmllcost	(*nreg(map(".pmllcost")))	/* short line cost */
#define n_ss		(*nreg(map(".ss")))	/* word space (.ss) */
#define n_sss		(*nreg(map(".sss")))	/* sentence space (.ss) */
#define n_ssh		(*nreg(map(".ssh")))	/* word space compression (.ssh) */
#define n_s0		(*nreg(map(".s0")))	/* last .s */
#define n_sv		(*nreg(map(".sv")))	/* .sv value */
#define n_lt		(*nreg(map(".lt")))	/* .lt value */
#define n_t0		(*nreg(map(".lt0")))	/* previous .lt value */
#define n_v0		(*nreg(map(".v0")))	/* last .v */
#define n_llx		(*nreg(map("bbllx")))	/* \w bounding box */
#define n_lly		(*nreg(map("bblly")))	/* \w bounding box */
#define n_urx		(*nreg(map("bburx")))	/* \w bounding box */
#define n_ury		(*nreg(map("bbury")))	/* \w bounding box */

/* functions for implementing read-only registers */
int f_nexttrap(void);	/* .t */
int f_divreg(void);	/* .z */
int f_hpos(void);	/* .k */