summaryrefslogtreecommitdiff
path: root/dviware/umddvi/h/binding.h
blob: 330ff2c17008a97aaee78bd6c9185ef9ceceaafc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* C-TeX function and variable bindings */

/*
 * Copyright (c) 1987 University of Maryland Department of Computer Science.
 * All rights reserved.  Permission to copy for any purpose is hereby granted
 * so long as this copyright notice remains intact.
 */

#ifdef StringSizeof
/*
 * If StringSizeof is defined, we assume that (sizeof "string_const") is
 * equal to (strlen("string_const") + 1); see the DefXXX macros below.
 */
#endif

/*
 * Here are the various flags that can be in the b_flags field of a struct
 * BoundName.
 */
#define BIsSpecial	1	/* a special int or dimen, or a font;
				   assignments to these are always
				   global */
#define BIsOuter	2	/* \outer, may not appear in macro def'n */
#define BIsLong		4	/* \long, may contain \outer s anyway */
#define BIsUndef	8	/* not defined anymore - used when a def'n
				   local to a group is destroyed by exiting
				   the group */

/*
 * SPECIAL
 * 1. Integers:
 *	\spacefactor \prevgraf \deadcycles \insertpenalties
 * 2. Dimens:
 *	\prevdepth \pagegoal \pagetotal \pagestretch \pagefilstretch
 *	\pagefillstretch \pagefilllstretch \pageshrink \pagedepth
 */

enum BindingKind {
	ProcBound, VarBound, IntBound, DimenBound, CodeBound,
	FontBound
};

union BindUnion {
	int	(*b_proc)();		/* iff ProcBound */
	struct	node *b_var;		/* iff VarBound */
	i32	*b_int;			/* iff IntBound */
	scaled	*b_dimen;		/* iff DimenBound */
	i32	b_code;			/* iff CodeBound */
	struct	FontInfo *b_font;	/* iff FontBound */
};

/*
 * The basic entity of C-TeX is the `BoundName'.  It is either a wired-in
 * procedure (e.g. \let, \def, \vskip) or variable (\hsize, \parskip), or a
 * user-defined macro/variable/whatnot.  These are indistinguishable from
 * one another (except that only wired procedures are ProcBound).
 *
 * There are also `CodeBound' things, which have no b_name and no b_flags.
 * In fact, they are really BoundNameCodes, but they need similar treatment,
 * so they get a similar structure.
 */
struct BoundName {
	enum	BindingKind b_binding;	/* the kind of thing it is */
	union	BindUnion b_bound;	/* the current binding */
	struct	SavedVal *b_AfterGroupRst;
					/* The saved value for restoration
					   after the current group.  This
					   is a pointer into the current
					   AfterGroupRst list. */
	struct	string b_name;		/* the name of this thing */
	int	b_flags;		/* various flags */
};

/*
 * \catcodes, \lccodes, etc are CodeBound, and are really arrays of these:
 */
struct BoundNameCode {
	enum	BindingKind b_binding;
	union	BindUnion b_bound;
	struct	SavedVal *b_AfterGroupRst;
};

/*
 * Saved values (changes that are local to a group) are stored in a doubly
 * linked list; this is so that constructs like
 *	{\advance\count0 by1 \global\advance\count0 by1}
 * can easily delete restorations that are no longer needed (having been
 * overridden by a \global operation).  In other words, we never have
 * any `save stack buildup'.  This requires the `spaghetti' below: a
 * current group level (so if b_AfterGroupRst is set, we can tell whether
 * the saved val is for this level) and moreover any inner saves for this
 * BoundName.
 *
 * To illustrate what is going on, suppose that we have count1==0.  Now we
 * begin group number 1, then 2.  Now we set count1 to 5, and since it has
 * no AfterGroupRst we save the 0 at level 2.  Now we increment count1, and
 * since it has an AfterGroupRst, we check the level.  It is 2; everything
 * is fine, and count1 is set to 6.  Now we begin group 3, and again increment
 * count1.  The level is 2, so we make a new SavedVal and set its level to
 * 3.  (We now have count1==7, save==6 when exiting level 3, save==0 when
 * exiting 2.)  Now the user does a \global\count1=42, so alas!, all those
 * saved values are useless.  To get rid of them, we delete the current
 * SavedVal, and its inner, and its inner's inner, and so forth, then clear
 * the AfterGroupRst pointer.  Voila!  A global \count1, set to 42.
 *
 * Note that we save CodeBound changes here too.  Since CodeBound objects
 * have no flags, some care is needed during restoration.
 */
struct SavedVal {
	int	sv_level;		/* the level to which this belongs */
	struct	SavedVal *sv_next;	/* linked list */
	struct	SavedVal *sv_prev;	/* or more precisely, queue */
	struct	SavedVal *sv_inner;	/* the inner saved value (from the
					   previous group that saved this) */
	union	BindUnion sv_val;	/* the saved value (note that saved
					   values are always the same type
					   as current values---i.e., types
					   are fixed) */
	struct	BoundName *sv_b;	/* the BoundName to which it belongs */
	int	sv_flags;		/* the saved b_flags (if applicable) */
};

struct	BoundName **NewNames;	/* during initialization, each internal
				   BoundName is stashed in the table to
				   which this points */

int	CurrentGroup;		/* the group level number of the current
				   group; incremented for { and decremented
				   for }, etc */

struct	SavedVal *AfterGroupRst;/* the current list for restoring locally
				   modified BoundNames */

/*
 * The following hackery will make the compiler complain in the event
 * of a dropped semicolon, without making lint complain.
 */
#ifdef lint
#define do_nothing	(void) rand()
#else
#define do_nothing	0
#endif

/*
 * Save a binding.
 */
#define SaveB(b) \
	if ((b)->b_AfterGroupRst == NULL || \
	    (b)->b_AfterGroupRst->sv_level != CurrentGroup) \
		DoSave(b); \
	else \
		do_nothing

/*
 * Undo a save.
 */
#define UnSaveB(b) \
	if ((b)->b_AfterGroupRst) \
		DoUnsave(b); \
	else \
		do_nothing

#ifdef StringSizeof
#define InitStrAndLen(str,cstr) (str.s_len = sizeof cstr-1, str.s_str = cstr)
#else
#define InitStrAndLen(str,cstr) (str.s_len = strlen(str.s_str = cstr))
#endif

#define SetBFlags(f)	NewNames[-1].b_flags |= (f)

#define DefIntVar(addr, name) { \
	static struct BoundName _b; \
	InitStrAndLen(_b.b_name, name); \
	_b.b_binding = IntBound; \
	_b.b_bound.b_int = addr; \
	*NewNames++ = &_b; \
}

#define DefDimenVar(addr, name) { \
	static struct BoundName _b; \
	InitStrAndLen(_b.b_name, name); \
	_b.b_binding = DimenBound; \
	_b.b_bound.b_dimen = addr; \
	*NewNames++ = &_b; \
}

#define DefProc(name, proc, flags) { \
	static struct BoundName _b; \
	InitStrAndLen(_b.b_name, name); \
	_b.b_binding = ProcBound; \
	_b.b_bound.b_proc = proc; \
	_b.b_bound.b_flags = flags; \
	*NewNames++ = &_b; \
}