1 /*	makeifont.c	(Berkeley)	1.8	86/03/04
2  *
3  * Font description file producer for imagen fonts:  David Slattengren
4  * Taken from vfontinfo by Andy Hertzfeld  4/79
5  *
6  *  Use:  makeifont [ -nNAME ]  [ -i -s -a -o -l -c ]  [ "-xs1,s2[;s1,s2...]" ]
7  *		[ "-ys1,s2[;s1,s2...]" ]  [ -p# ]  [ -r# ]  [ -ddir ]  font
8  *
9  *	Mkfnt takes the font named "font" and produces a ditroff description
10  *	file from it.  The -n option takes the 1 or 2 letter troff name to put
11  *	the description (default = XX).  The -s, -o, -i, -a options select a
12  *	different character mapping than for a "roman" font.  s = special;
13  *	o = math;  i = italics;  a = ascii.  The -l option tells if the font
14  *	has ligatures.  The -c option tells makeifont that the font is a
15  *	constant width one and sets parameters appropriately.
16  *
17  *	Both -x and -y options allow character name mapping.  A semi-colon
18  *	separated list of comma-separated character-name pairs follows the
19  *	x or y.  Notice that there are no spaces in the -x or -y command.  It
20  *	is also IMPORTANT to enclose these arguments in single quotes to stop
21  *	the cshell from interpretting the contents.  A -x pair REPLACES the
22  *	definition for s1 by s2.  A -y pair creates a synonym for s1 and calls
23  *	it s2.  -x and -y MUST be sent after -s, -m, -i, or -a  if one of them
24  *	is used.  Some synonyms are defaulted.  To remove a synonym or char-
25  *	acter, leave out s2.
26  *
27  *	The -p# option tells what point size the DESC file has
28  *	as it's "unitwidth" argument (default: 40).  The -r# option is the
29  *	resolution of the device (default: 240, in units/inch).  The -d option
30  *	tells where to find fonts (default: /usr/src/local/imagen/fonts/raster).
31  */
32 
33 /*
34  *  Here's an ascii character set, just in case you need it:
35 
36      | 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel|
37      | 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si |
38      | 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb|
39      | 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us |
40      | 20 sp | 21  ! | 22  " | 23  # | 24  $ | 25  % | 26  & | 27  ' |
41      | 28  ( | 29  ) | 2a  * | 2b  + | 2c  , | 2d  - | 2e  . | 2f  / |
42      | 30  0 | 31  1 | 32  2 | 33  3 | 34  4 | 35  5 | 36  6 | 37  7 |
43      | 38  8 | 39  9 | 3a  : | 3b  ; | 3c  < | 3d  = | 3e  > | 3f  ? |
44      | 40  @ | 41  A | 42  B | 43  C | 44  D | 45  E | 46  F | 47  G |
45      | 48  H | 49  I | 4a  J | 4b  K | 4c  L | 4d  M | 4e  N | 4f  O |
46      | 50  P | 51  Q | 52  R | 53  S | 54  T | 55  U | 56  V | 57  W |
47      | 58  X | 59  Y | 5a  Z | 5b  [ | 5c  \ | 5d  ] | 5e  ^ | 5f  _ |
48      | 60  ` | 61  a | 62  b | 63  c | 64  d | 65  e | 66  f | 67  g |
49      | 68  h | 69  i | 6a  j | 6b  k | 6c  l | 6d  m | 6e  n | 6f  o |
50      | 70  p | 71  q | 72  r | 73  s | 74  t | 75  u | 76  v | 77  w |
51      | 78  x | 79  y | 7a  z | 7b  { | 7c  | | 7d  } | 7e  ~ | 7f del|
52 
53  *
54  */
55 
56 #include <stdio.h>
57 #include <ctype.h>
58 #include "rst.h"
59 
60 char 	sccsid[] = "@(#)makeifont.c	1.8	(Berkeley)	03/04/86";
61 
62 #define PCNTUP		62	/* percent of maximum height for an ascender */
63 #define PCNTDOWN	73	/* percent of maximum droop for a descender */
64 #ifndef BITDIR
65 #define BITDIR		"/usr/src/local/imagen/fonts/raster"
66 #endif
67 #define POINTSIZE	40	/* this is the "unitwidth" point size */
68 #define MINSIZE		6	/* the minimum and maximum point size values */
69 #define MAXSIZE		36	/*    acceptible for use as "unitwidth"s */
70 #define MINRES		10	/* check up on resolution input by setting */
71 #define MAXRES		100000	/*    absurdly out-of-range limits on them */
72 #define MAXLAST		127	/* highest character code allowed */
73 #define SYNON		100	/* number of entries in a synonym table. */
74 				/*    equals twice the number of pairs. */
75 
76 
77 unsigned char *idstrings;	/* place for identifying strings */
78 unsigned char *endstring;	/* points to end of id strings */
79 double	fixtowdth;		/* "fix" and magnification conversion factor */
80 glyph_dir g[DIRSIZ];		/* directory of glyph definitions */
81 preamble p;			/* set of variables for preamble */
82 
83 int	res = RES;		/* resolution of the device (units/inch) */
84 double	fixpix = FIXPIX;	/* conversion factor "fix"es to pixels */
85 int	pointsize = POINTSIZE;	/* point size being used for unitwidth */
86 int	psize;			/* point size of font actually used */
87 int	psizelist[] = { 40, 36, 28, 24, 22, 20, 18, 16,
88 			14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 0 };
89 
90 char	*fontname = "XX";	/* troff name of font - set on command line */
91 char	*fontdir = BITDIR;	/* place to look for fonts */
92 char	IName[100];		/* input file name put here */
93 char	*rdchar ();		/* function makes strings for ascii */
94 FILE *	FID = NULL;		/* input file number */
95 
96 int	maxdown = 0;		/* size of the most "droopy" character */
97 int	maxup = 0;		/* size of the tallest character */
98 int	type;			/* 1, 2, or 3 for type of ascend/descending */
99 int	ligsf = 0;		/* flag "does this font have ligatures?" */
100 int	constant = 0;		/* flag constant width font (spacewidth, etc.)*/
101 
102 				/* following are the character maps for */
103 				/* ascii code-conversion to printables... */
104 char	**charmap;
105 char	**synonyms;
106 int	numsyn;
107 
108 char *iregular[] = {
109 	"*G", "*D", "*H", "*L", "*C", "*P", "*S", "*U", "*F", "*Q", "*W",
110 	"id", "ij", "ga", "aa", "^", "d^", "hc", "rn", "..", "~", "ve",
111 	"im", "de", "ce", "tl", "ar", "fb", "ae", "oe", "AE", "OE", "o/",
112 	"!", "\"", "fm", "ft", "%", "&", "'", "(", ")", "*", "+", ",", "hy",
113 	".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";",
114 	"<", "=", ">", "?",
115 	"es", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
116 	"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[",
117 	"b\"", "]", "\\-", "em", "`", "a", "b", "c", "d", "e", "f", "g", "h",
118 	"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
119 	"w", "x", "y", "z", "ff", "fi", "fl", "Fi", "Fl"
120 };
121 int	nregular = 14;
122 char *sregular[SYNON] = {
123 	"A", "*A",	"B", "*B",	"E", "*E",	"H", "*Y",
124 	"I", "*I",	"K", "*K",	"M", "*M",	"N", "*N",
125 	"O", "*O",	"P", "*R",	"T", "*T",	"X", "*X",
126 	"Z", "*Z",	"hy", "-"
127 };
128 
129 char *iascii[] = {
130 	"m.", "da", "*a", "*b", "an", "no", "mo", "*p", "*l", "*g", "*d",
131 	"is", "+-", "O+", "if", "pd", "sb", "sp", "ca", "cu", "fa", "te",
132 	"OX", "<>", "<-", "->", "ap", "!=", "<=", ">=", "==", "or", "",
133 	"!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-",
134 	".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";",
135 	"<", "=", ">", "?",
136 	"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
137 	"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[",
138 	"\\", "]", "^", "em", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i",
139 	"j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
140 	"x", "y", "z", "{", "|", "}", "~", "dm"
141 };
142 int	nascii = 2;
143 char *sascii[SYNON] = {
144 	"-", "hy",	"-", "\\-"
145 };
146 
147 char *ispecial[] = {
148 	"mi", "m.", "mu", "**", "\\", "ci", "+-", "-+", "O+", "O-", "OX", "O/",
149 	"O.", "di", "ht", "bu", "pe", "==", "ib", "ip", "<=", ">=", "(=", ")=",
150 	"ap", "pt", "sb", "sp", "!=", ".=", "((", "))", "<-", "->", "ua", "da",
151 	"<>", "<<", ">>", "~=", "lh", "rh", "Ua", "Da", "><", "uL", "uR", "lR",
152 	"fm", "if", "mo", "!m", "0/", "ul", "al", ")(", "fa", "te", "no", "?0",
153 	"?1", "?2", "cr", "", "/", "A", "B", "C", "D", "E", "F", "G", "H", "I",
154 	"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
155 	"X", "Y", "Z", "cu", "ca", "c+", "an", "or", "|-", "-|", "lf", "rf",
156 	"lc", "rc", "{", "}", "<", ">", "br", "||", "[[", "]]", "", "", "sr",
157 	"#", "gr", "is", "ux", "dx", "rx", "dm", "sc", "dg", "dd", "pp", "@",
158 	"co", "", "$"
159 };
160 int	nspecial = 2;
161 char *sspecial[SYNON] = {
162 	"lh", "La",	"rh", "Ra"
163 };
164 
165 char *imath[] = {
166 	"Bl", "Br", "LT", "RT", "LB", "RB", "rt", "rk", "rb", "lt", "lk", "lb",
167 	"rc", "lc", "rf", "lf", "bv", "ci", "^R", "^S", "^T", "^U", "^V", "^W",
168 	"^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_",
169 	" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-",
170 	".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";",
171 	"<", "=", ">", "?",
172 	"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
173 	"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[",
174 	"\\", "]", "^", "em", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i",
175 	"j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
176 	"x", "y", "z", "{", "|", "}", "~", "dm"
177 };
178 int	nmath = 0;
179 char *smath[SYNON] = {
180 	"",""
181 };
182 
183 char *iitalics[] = {
184 	"*G", "*D", "*H", "*L", "*C", "*P", "*S", "*U", "*F", "*Q", "*W",
185 	"*a", "*b", "*g", "*d", "*e", "*z", "*y", "*h", "*i", "*k", "*l",
186 	"*m", "*n", "*c", "*p", "*r", "*s", "*t", "*u", "*f", "*x", "id",
187 	"!", "\"", "el", "Fi", "pd", "&", "'", "(", ")", "*", "+", ",", "hy",
188 	".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";",
189 	"<", "=", ">", "?",
190 	"id", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
191 	"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[",
192 	"ff", "]", "fi", "fl", "`", "a", "b", "c", "d", "e", "f", "g", "h",
193 	"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
194 	"w", "x", "y", "z", "*q", "*w", "?2", "?1", "Fl"
195 };
196 int	nitalics = 15;
197 char *sitalics[SYNON] = {
198 	"A", "*A",	"B", "*B",	"E", "*E",	"H", "*Y",
199 	"I", "*I",	"K", "*K",	"M", "*M",	"N", "*N",
200 	"O", "*O",	"P", "*R",	"T", "*T",	"X", "*X",
201 	"Z", "*Z",	"o", "*o",	"hy", "-"
202 };
203 
204 
205 
206 main (argc, argv)
207 int argc;
208 char **argv;
209 {
210     register int i;		/* two indexes */
211     register int j;
212     register char *ptr;		/* string traveller */
213     register char delimit;	/* place for delemiters on command-line */
214     char *replacelist = NULL;	/* list of character-name replacements */
215     char *synonymlist = NULL;	/* list of synonym entries */
216     char tostring();		/* function makes string */
217     char *nextstring();		/* moves to next string on list */
218     char *operand();		/* reads operands from commandline */
219 
220     charmap = iregular;			/* default character map */
221     synonyms = sregular;
222     numsyn = nregular;
223     while (--argc > 0 && *(*(++argv)) == '-') {	/* do options... */
224 	switch ((*argv)[1]) {
225 
226 	  case 's': charmap = ispecial;		/* special font */
227 		    synonyms = sspecial;
228 		    numsyn = nspecial;
229 		    break;
230 
231 	  case 'o': charmap = imath;		/* math font */
232 		    synonyms = smath;
233 		    numsyn = nmath;
234 		    break;
235 
236 	  case 'i': charmap = iitalics;		/* italics font */
237 		    synonyms = sitalics;
238 		    numsyn = nitalics;
239 		    break;
240 
241 	  case 'a': charmap = iascii;		/* ascii font */
242 		    synonyms = sascii;
243 		    numsyn = nascii;
244 		    break;
245 
246 	  case 'c': constant = 1;		/* constant width font */
247 		    break;
248 
249 	  case 'l': ligsf = 1;			/* ascii font */
250 		    break;
251 
252 	  case 'n': fontname = operand(&argc, &argv);	/* troff font name */
253 		    break;
254 
255 	  case 'x': replacelist = operand(&argc, &argv);   /* replacements */
256 		    break;
257 
258 	  case 'y': synonymlist = operand(&argc, &argv);	/* synonyms */
259 		    break;
260 
261 	  case 'd': fontdir = operand(&argc, &argv);		/* directory */
262 		    break;
263 
264 	  case 'p': pointsize = atoi(operand(&argc, &argv));	/* point size */
265 		    if (pointsize < MINSIZE || pointsize > MAXSIZE)
266 			error("illegal point size: %d", pointsize);
267 		    break;
268 
269 	  case 'r': res = atoi(operand(&argc, &argv));	/* resolution */
270 		    if (res < MINRES || res > MAXRES)
271 			error("illegal resolution: %d", res);
272 		    fixpix = (FIXIN * res);		/* pixels per fix */
273 		    break;
274 
275 	   default: error("bad option: %c", **argv);
276 	}
277     }
278 
279     if (replacelist != NULL) {
280 	ptr = replacelist;
281 	while (delimit = tostring(ptr, ',')) {		/* get s1 */
282 	    for (i = 0; i <= MAXLAST; i++)		/* search for match */
283 		if (strcmp (charmap[i], ptr) == 0)
284 		    break;
285 	    if (i > MAXLAST) error("-x option: no match");
286 	    charmap[i] = ptr = nextstring(ptr);		/* replace s1 */
287 	    delimit = tostring(ptr, ':');		/* with string s2 */
288 	    if (delimit) ptr = nextstring(ptr);
289 	}
290     }
291 
292     if (synonymlist != NULL) {
293 	ptr = synonymlist;
294 	while (delimit = tostring(ptr, ',')) {	/* get s1 */
295 	    synonyms[2 * numsyn] = ptr;		/* set on end of list */
296 	    ptr = nextstring(ptr);		/* get string s2 */
297 	    delimit = tostring(ptr, ':');
298 	    if (*ptr) {				/* if something there */
299 		synonyms[2 * numsyn++ + 1] = ptr;	/* add to list */
300 	    } else {				/* otherwise */
301 		for (i = 0; i < numsyn; i++) {		/* remove from list */
302 		    if (!strcmp(synonyms[2*i],synonyms[2*numsyn])) {
303 			numsyn--;
304 			for (j = i--; j < numsyn; j++) {
305 			    synonyms[2 * j] = synonyms[2 * (j+1)];
306 			    synonyms[2*j + 1] = synonyms[2*j + 3];
307 			}
308 		    }
309 		}
310 	    }
311 	    if (delimit) ptr = nextstring(ptr);
312 	    if (numsyn > SYNON) error("out of synonym space");
313 	}
314     }
315 
316     if (argc != 1)					/* open font file */
317 	error("An RST font filename must be the last option");
318     for (i = 0; FID == NULL && (psize = psizelist[i]) > 0; i++) {
319 	sprintf (IName, "%s/%s.r%d", fontdir, *argv, psize);
320 	FID = fopen (IName, "r");
321     }
322     if (FID == NULL)
323 	error("can't find %s", *argv);
324 
325     for (i = 0; i < FMARK; filemark[i++] = getc(FID));
326     if (strncmp(filemark, "Rast", 4))
327 	    error("bad File Mark in Font file.");
328 
329     p.p_size = rd2();
330     p.p_version = rd1();
331     if (p.p_version)
332 	error("wrong version of Font file.");
333     p.p_glyph = rd3();
334     p.p_first = rd2();
335     p.p_last = rd2();
336     if (p.p_last > MAXLAST) {
337 	fprintf(stderr, "truncating from %d to %d\n", p.p_last, MAXLAST);
338 	p.p_last = MAXLAST;
339     }
340     p.p_mag = rd4();
341     p.p_desiz = rd4();
342     p.p_linesp = rd4();
343     p.p_wordsp = rd4();
344     p.p_rot = rd2();
345     p.p_cadv = rd1();
346     p.p_ladv = rd1();
347     p.p_id = rd4();
348     p.p_res = rd2();
349     if (p.p_res != res)
350 	    error("wrong resolution in Font file.");
351 
352     i = p.p_glyph - 44;
353     idstrings = (unsigned char *) malloc (i);
354     endstring = idstrings + i;
355     while (i--) if (getc(FID) == EOF)
356 	    error("bad preamble in Font file.");
357 
358     for (i = p.p_first; i <= p.p_last; i++) {
359 	    g[i].g_height = rd2();
360 	    g[i].g_width = rd2();
361 	    g[i].g_up = rd2();
362 	    g[i].g_left = rd2();
363 	    g[i].g_pwidth = rd4();
364 	    g[i].g_bitp = rd3();
365     }
366 
367 
368     if ((fixtowdth = fixpix * p.p_mag / 1000.0) == 0.0)
369 	fixtowdth = fixpix;
370 
371     printf("# Font %s\n# size %.2f, ", IName, p.p_desiz * FIX);
372     printf("first %d, last %d, res %d, ", p.p_first, p.p_last, p.p_res);
373     printf("mag %.2f\n", fixtowdth / fixpix);
374 
375     printf("name %s\n", fontname);
376     if (ligsf)
377 	printf ("ligatures ff fl fi ffl ffi 0\n");
378     if ((i = (pointsize * p.p_wordsp * fixtowdth) / psize) > 127) i = 127;
379     printf("spacewidth %d\n", i);
380     printf ("# char	width	u/d	octal\ncharset\n");
381 			/* the octal values for the following characters are */
382 			/* purposefully OUT of the range of characters (128) */
383     printf ("\\|	%4d	 0	0%o\n\\^	%4d	 0	0%o\n",
384 		(constant ? i : i/3), DIRSIZ, (constant ? 0 : i/6), DIRSIZ);
385 
386     for (j = p.p_first; j <= p.p_last; j++) {
387 	if (g[j].g_bitp != 0) {
388 	    if (g[j].g_up > maxup) maxup = g[j].g_up;
389 	    if ((i = g[j].g_height - (g[j].g_up + 1)) > maxdown) maxdown = i;
390 	}
391     }
392     if (maxdown == 0) maxdown = 1;
393 
394 /*******************************************************************************
395 
396 	`type' is used to determine overhangs (up/down) from percentage of
397 	the maximum heights and dips.  Ascenders are higher than PCNTUP%
398 	of the highest, as descenders are more than PCNTDOWN%.
399 	widths [i = f(width)] are calculated from the definition point
400 	size (pointsize) and the one from this font (psize).
401 
402 *******************************************************************************/
403 
404     for (j=0; j<DIRSIZ; j++) {
405 	if (g[j].g_bitp != 0) {
406 	    type = (int) (((g[j].g_up * 100) / maxup) > PCNTUP) * 2 | (int)
407 	    	((((g[j].g_height - (g[j].g_up+1)) * 100)/maxdown) > PCNTDOWN);
408 	    if (*(ptr = charmap[j])) {
409 		printf ("%s	%4d	 %d	0%o\n", ptr, (int) (pointsize
410 			* g[j].g_pwidth * fixtowdth / psize), type, j);
411 		for (i = 0; i < numsyn; i++)
412 		    if (strcmp (ptr, synonyms[2 * i]) == 0)
413 			printf ("%s	\"\n", synonyms[2 * i + 1]);
414 	    }
415 	}
416     } /* for j */
417     exit(0);
418 }
419 
420 
421 /*----------------------------------------------------------------------------*
422  | Routine:	char  * operand (& argc,  & argv)
423  |
424  | Results:	returns address of the operand given with a command-line
425  |		option.  It uses either "-Xoperand" or "-X operand", whichever
426  |		is present.  The program is terminated if no option is present.
427  |
428  | Side Efct:	argc and argv are updated as necessary.
429  *----------------------------------------------------------------------------*/
430 
431 char *operand(argcp, argvp)
432 int * argcp;
433 char ***argvp;
434 {
435 	if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
436 	if ((--*argcp) <= 0)			/* no operand */
437 	    error("command-line option operand missing.");
438 	return(*(++(*argvp)));			/* operand operand */
439 }
440 
441 
442 /*----------------------------------------------------------------------------*
443  | Routine:	char  tostring (pointer, delimitter)
444  |
445  | Results:	checks string pointed to by pointer and turns it into a
446  |		string at 'delimitter' by replacing it with '\0'.  If the
447  |		end of the string is found first, '\0' is returned; otherwise
448  |		the delimitter found there is returned.
449  |
450  *----------------------------------------------------------------------------*/
451 
452 char tostring(p, d)
453 register char *p;
454 register char d;
455 {
456     while (*p && *p != d) p++;
457     d = *p;
458     *p = '\0';
459     return d;
460 }
461 
462 
463 /*----------------------------------------------------------------------------*
464  | Routine:	char  * nextstring (pointer)
465  |
466  | Results:	returns address of next string after one pointed to by
467  |		pointer.  The next string is after the '\0' byte.
468  |
469  *----------------------------------------------------------------------------*/
470 
471 char *nextstring(p)
472 register char *p;
473 {
474     while (*(p++));
475     return p;
476 }
477 
478 
479 /*VARARGS1*/
480 error(string, a1, a2, a3, a4)
481 char *string;
482 {
483     fprintf(stderr, "makefont: ");
484     fprintf(stderr, string, a1, a2, a3, a4);
485     fprintf(stderr, "\n");
486     exit(8);
487 }
488 
489 rd1()
490 {
491     int i;
492 
493     if((i = getc(FID)) == EOF) error("file read error");
494     return i;
495 }
496 
497 rd2()
498 {
499     register int i = rd1() << 8;
500 
501     return i + rd1();
502 }
503 
504 rd3()
505 {
506     register int i = rd2() << 8;
507 
508     return i + rd1();
509 }
510 
511 rd4()
512 {
513     register int i = rd2() << 16;
514 
515     return i + rd2();
516 }
517