xref: /inferno-os/appl/cmd/man2html.b (revision 7cdb1d14cab5ad4eceb9edfc484ea272cf8a062d)
10e96539fSCharles.Forsythimplement Man2html;
20e96539fSCharles.Forsyth
30e96539fSCharles.Forsythinclude "sys.m";
40e96539fSCharles.Forsyth	stderr: ref Sys->FD;
50e96539fSCharles.Forsyth	sys: Sys;
60e96539fSCharles.Forsyth	print, fprint, sprint: import sys;
70e96539fSCharles.Forsyth
80e96539fSCharles.Forsyth
90e96539fSCharles.Forsythinclude "bufio.m";
100e96539fSCharles.Forsyth
110e96539fSCharles.Forsythinclude "draw.m";
120e96539fSCharles.Forsyth
130e96539fSCharles.Forsythinclude "daytime.m";
140e96539fSCharles.Forsyth	dt: Daytime;
150e96539fSCharles.Forsyth
160e96539fSCharles.Forsythinclude "string.m";
170e96539fSCharles.Forsyth	str: String;
180e96539fSCharles.Forsyth
1930dcb98cSCharles.Forsythinclude "arg.m";
2030dcb98cSCharles.Forsyth
210e96539fSCharles.ForsythMan2html: module
220e96539fSCharles.Forsyth{
230e96539fSCharles.Forsyth	init:	fn(ctxt: ref Draw->Context, args: list of string);
240e96539fSCharles.Forsyth};
250e96539fSCharles.Forsyth
260e96539fSCharles.ForsythRuneself: con 16r80;
270e96539fSCharles.Forsythfalse, true: con iota;
280e96539fSCharles.Forsyth
290e96539fSCharles.ForsythTroffspec: adt {
300e96539fSCharles.Forsyth	name: string;
310e96539fSCharles.Forsyth	value: string;
320e96539fSCharles.Forsyth};
330e96539fSCharles.Forsyth
340e96539fSCharles.Forsythtspec := array [] of { Troffspec
350e96539fSCharles.Forsyth	("ff", "ff"),
360e96539fSCharles.Forsyth	("fi", "fi"),
370e96539fSCharles.Forsyth	("fl", "fl"),
380e96539fSCharles.Forsyth	("Fi", "ffi"),
390e96539fSCharles.Forsyth	("ru", "_"),
401bc0e0d5SCharles.Forsyth	("em", "—"),
410e96539fSCharles.Forsyth	("14", "¼"),
420e96539fSCharles.Forsyth	("12", "½"),
430e96539fSCharles.Forsyth	("co", "©"),
440e96539fSCharles.Forsyth	("de", "°"),
450e96539fSCharles.Forsyth	("dg", "¡"),
460e96539fSCharles.Forsyth	("fm", "´"),
470e96539fSCharles.Forsyth	("rg", "®"),
480e96539fSCharles.Forsyth#	("bu", "*"),
490e96539fSCharles.Forsyth	("bu", "•"),
500e96539fSCharles.Forsyth	("sq", "¤"),
510e96539fSCharles.Forsyth	("hy", "-"),
520e96539fSCharles.Forsyth	("pl", "+"),
530e96539fSCharles.Forsyth	("mi", "-"),
540e96539fSCharles.Forsyth	("mu", "×"),
550e96539fSCharles.Forsyth	("di", "÷"),
560e96539fSCharles.Forsyth	("eq", "="),
570e96539fSCharles.Forsyth	("==", "=="),
580e96539fSCharles.Forsyth	(">=", ">="),
590e96539fSCharles.Forsyth	("<=", "<="),
600e96539fSCharles.Forsyth	("!=", "!="),
610e96539fSCharles.Forsyth	("+-", "&#177;"),
620e96539fSCharles.Forsyth	("no", "&#172;"),
630e96539fSCharles.Forsyth	("sl", "/"),
640e96539fSCharles.Forsyth	("ap", "&"),
650e96539fSCharles.Forsyth	("~=", "~="),
660e96539fSCharles.Forsyth	("pt", "oc"),
670e96539fSCharles.Forsyth	("gr", "GRAD"),
680e96539fSCharles.Forsyth	("->", "->"),
690e96539fSCharles.Forsyth	("<-", "<-"),
700e96539fSCharles.Forsyth	("ua", "^"),
710e96539fSCharles.Forsyth	("da", "v"),
720e96539fSCharles.Forsyth	("is", "Integral"),
730e96539fSCharles.Forsyth	("pd", "DIV"),
740e96539fSCharles.Forsyth	("if", "oo"),
750e96539fSCharles.Forsyth	("sr", "-/"),
760e96539fSCharles.Forsyth	("sb", "(~"),
770e96539fSCharles.Forsyth	("sp", "~)"),
780e96539fSCharles.Forsyth	("cu", "U"),
790e96539fSCharles.Forsyth	("ca", "(^)"),
800e96539fSCharles.Forsyth	("ib", "(="),
810e96539fSCharles.Forsyth	("ip", "=)"),
820e96539fSCharles.Forsyth	("mo", "C"),
830e96539fSCharles.Forsyth	("es", "&Oslash;"),
840e96539fSCharles.Forsyth	("aa", "&#180;"),
850e96539fSCharles.Forsyth	("ga", "`"),
860e96539fSCharles.Forsyth	("ci", "O"),
870e96539fSCharles.Forsyth	("L1", "Lucent"),
880e96539fSCharles.Forsyth	("sc", "&#167;"),
890e96539fSCharles.Forsyth	("dd", "++"),
900e96539fSCharles.Forsyth	("lh", "<="),
910e96539fSCharles.Forsyth	("rh", "=>"),
920e96539fSCharles.Forsyth	("lt", "("),
930e96539fSCharles.Forsyth	("rt", ")"),
940e96539fSCharles.Forsyth	("lc", "|"),
950e96539fSCharles.Forsyth	("rc", "|"),
960e96539fSCharles.Forsyth	("lb", "("),
970e96539fSCharles.Forsyth	("rb", ")"),
980e96539fSCharles.Forsyth	("lf", "|"),
990e96539fSCharles.Forsyth	("rf", "|"),
1000e96539fSCharles.Forsyth	("lk", "|"),
1010e96539fSCharles.Forsyth	("rk", "|"),
1020e96539fSCharles.Forsyth	("bv", "|"),
1030e96539fSCharles.Forsyth	("ts", "s"),
1040e96539fSCharles.Forsyth	("br", "|"),
1050e96539fSCharles.Forsyth	("or", "|"),
1060e96539fSCharles.Forsyth	("ul", "_"),
1070e96539fSCharles.Forsyth	("rn", " "),
1080e96539fSCharles.Forsyth	("*p", "PI"),
1090e96539fSCharles.Forsyth	("**", "*"),
1100e96539fSCharles.Forsyth};
1110e96539fSCharles.Forsyth
1120e96539fSCharles.Forsyth	Entity: adt {
1130e96539fSCharles.Forsyth		 name: string;
1140e96539fSCharles.Forsyth		 value: int;
1150e96539fSCharles.Forsyth	};
1160e96539fSCharles.Forsyth	Entities: array of Entity;
1170e96539fSCharles.Forsyth
1180e96539fSCharles.ForsythEntities = array[] of {
1190e96539fSCharles.Forsyth		Entity( "&#161;",	'¡' ),
1200e96539fSCharles.Forsyth		Entity( "&#162;",	'¢' ),
1210e96539fSCharles.Forsyth		Entity( "&#163;",	'£' ),
1220e96539fSCharles.Forsyth		Entity( "&#164;",	'¤' ),
1230e96539fSCharles.Forsyth		Entity( "&#165;",	'¥' ),
1240e96539fSCharles.Forsyth		Entity( "&#166;",	'¦' ),
1250e96539fSCharles.Forsyth		Entity( "&#167;",	'§' ),
1260e96539fSCharles.Forsyth		Entity( "&#168;",	'¨' ),
1270e96539fSCharles.Forsyth		Entity( "&#169;",	'©' ),
1280e96539fSCharles.Forsyth		Entity( "&#170;",	'ª' ),
1290e96539fSCharles.Forsyth		Entity( "&#171;",	'«' ),
1300e96539fSCharles.Forsyth		Entity( "&#172;",	'¬' ),
1310e96539fSCharles.Forsyth		Entity( "&#173;",	'­' ),
1320e96539fSCharles.Forsyth		Entity( "&#174;",	'®' ),
1330e96539fSCharles.Forsyth		Entity( "&#175;",	'¯' ),
1340e96539fSCharles.Forsyth		Entity( "&#176;",	'°' ),
1350e96539fSCharles.Forsyth		Entity( "&#177;",	'±' ),
1360e96539fSCharles.Forsyth		Entity( "&#178;",	'²' ),
1370e96539fSCharles.Forsyth		Entity( "&#179;",	'³' ),
1380e96539fSCharles.Forsyth		Entity( "&#180;",	'´' ),
1390e96539fSCharles.Forsyth		Entity( "&#181;",	'µ' ),
1400e96539fSCharles.Forsyth		Entity( "&#182;",	'¶' ),
1410e96539fSCharles.Forsyth		Entity( "&#183;",	'·' ),
1420e96539fSCharles.Forsyth		Entity( "&#184;",	'¸' ),
1430e96539fSCharles.Forsyth		Entity( "&#185;",	'¹' ),
1440e96539fSCharles.Forsyth		Entity( "&#186;",	'º' ),
1450e96539fSCharles.Forsyth		Entity( "&#187;",	'»' ),
1460e96539fSCharles.Forsyth		Entity( "&#188;",	'¼' ),
1470e96539fSCharles.Forsyth		Entity( "&#189;",	'½' ),
1480e96539fSCharles.Forsyth		Entity( "&#190;",	'¾' ),
1490e96539fSCharles.Forsyth		Entity( "&#191;",	'¿' ),
1500e96539fSCharles.Forsyth		Entity( "&Agrave;",	'À' ),
1510e96539fSCharles.Forsyth		Entity( "&Aacute;",	'Á' ),
1520e96539fSCharles.Forsyth		Entity( "&Acirc;",	'Â' ),
1530e96539fSCharles.Forsyth		Entity( "&Atilde;",	'Ã' ),
1540e96539fSCharles.Forsyth		Entity( "&Auml;",	'Ä' ),
1550e96539fSCharles.Forsyth		Entity( "&Aring;",	'Å' ),
1560e96539fSCharles.Forsyth		Entity( "&AElig;",	'Æ' ),
1570e96539fSCharles.Forsyth		Entity( "&Ccedil;",	'Ç' ),
1580e96539fSCharles.Forsyth		Entity( "&Egrave;",	'È' ),
1590e96539fSCharles.Forsyth		Entity( "&Eacute;",	'É' ),
1600e96539fSCharles.Forsyth		Entity( "&Ecirc;",	'Ê' ),
1610e96539fSCharles.Forsyth		Entity( "&Euml;",	'Ë' ),
1620e96539fSCharles.Forsyth		Entity( "&Igrave;",	'Ì' ),
1630e96539fSCharles.Forsyth		Entity( "&Iacute;",	'Í' ),
1640e96539fSCharles.Forsyth		Entity( "&Icirc;",	'Î' ),
1650e96539fSCharles.Forsyth		Entity( "&Iuml;",	'Ï' ),
1660e96539fSCharles.Forsyth		Entity( "&ETH;",	'Ð' ),
1670e96539fSCharles.Forsyth		Entity( "&Ntilde;",	'Ñ' ),
1680e96539fSCharles.Forsyth		Entity( "&Ograve;",	'Ò' ),
1690e96539fSCharles.Forsyth		Entity( "&Oacute;",	'Ó' ),
1700e96539fSCharles.Forsyth		Entity( "&Ocirc;",	'Ô' ),
1710e96539fSCharles.Forsyth		Entity( "&Otilde;",	'Õ' ),
1720e96539fSCharles.Forsyth		Entity( "&Ouml;",	'Ö' ),
1730e96539fSCharles.Forsyth		Entity( "&215;",	'×' ),
1740e96539fSCharles.Forsyth		Entity( "&Oslash;",	'Ø' ),
1750e96539fSCharles.Forsyth		Entity( "&Ugrave;",	'Ù' ),
1760e96539fSCharles.Forsyth		Entity( "&Uacute;",	'Ú' ),
1770e96539fSCharles.Forsyth		Entity( "&Ucirc;",	'Û' ),
1780e96539fSCharles.Forsyth		Entity( "&Uuml;",	'Ü' ),
1790e96539fSCharles.Forsyth		Entity( "&Yacute;",	'Ý' ),
1800e96539fSCharles.Forsyth		Entity( "&THORN;",	'Þ' ),
1810e96539fSCharles.Forsyth		Entity( "&szlig;",	'ß' ),
1820e96539fSCharles.Forsyth		Entity( "&agrave;",	'à' ),
1830e96539fSCharles.Forsyth		Entity( "&aacute;",	'á' ),
1840e96539fSCharles.Forsyth		Entity( "&acirc;",	'â' ),
1850e96539fSCharles.Forsyth		Entity( "&atilde;",	'ã' ),
1860e96539fSCharles.Forsyth		Entity( "&auml;",	'ä' ),
1870e96539fSCharles.Forsyth		Entity( "&aring;",	'å' ),
1880e96539fSCharles.Forsyth		Entity( "&aelig;",	'æ' ),
1890e96539fSCharles.Forsyth		Entity( "&ccedil;",	'ç' ),
1900e96539fSCharles.Forsyth		Entity( "&egrave;",	'è' ),
1910e96539fSCharles.Forsyth		Entity( "&eacute;",	'é' ),
1920e96539fSCharles.Forsyth		Entity( "&ecirc;",	'ê' ),
1930e96539fSCharles.Forsyth		Entity( "&euml;",	'ë' ),
1940e96539fSCharles.Forsyth		Entity( "&igrave;",	'ì' ),
1950e96539fSCharles.Forsyth		Entity( "&iacute;",	'í' ),
1960e96539fSCharles.Forsyth		Entity( "&icirc;",	'î' ),
1970e96539fSCharles.Forsyth		Entity( "&iuml;",	'ï' ),
1980e96539fSCharles.Forsyth		Entity( "&eth;",	'ð' ),
1990e96539fSCharles.Forsyth		Entity( "&ntilde;",	'ñ' ),
2000e96539fSCharles.Forsyth		Entity( "&ograve;",	'ò' ),
2010e96539fSCharles.Forsyth		Entity( "&oacute;",	'ó' ),
2020e96539fSCharles.Forsyth		Entity( "&ocirc;",	'ô' ),
2030e96539fSCharles.Forsyth		Entity( "&otilde;",	'õ' ),
2040e96539fSCharles.Forsyth		Entity( "&ouml;",	'ö' ),
2050e96539fSCharles.Forsyth		Entity( "&247;",	'÷' ),
2060e96539fSCharles.Forsyth		Entity( "&oslash;",	'ø' ),
2070e96539fSCharles.Forsyth		Entity( "&ugrave;",	'ù' ),
2080e96539fSCharles.Forsyth		Entity( "&uacute;",	'ú' ),
2090e96539fSCharles.Forsyth		Entity( "&ucirc;",	'û' ),
2100e96539fSCharles.Forsyth		Entity( "&uuml;",	'ü' ),
2110e96539fSCharles.Forsyth		Entity( "&yacute;",	'ý' ),
2120e96539fSCharles.Forsyth		Entity( "&thorn;",	'þ' ),
2130e96539fSCharles.Forsyth		Entity( "&yuml;",	'ÿ' ),		# &#255;
2140e96539fSCharles.Forsyth
2150e96539fSCharles.Forsyth		Entity( "&#SPACE;",	' ' ),
2160e96539fSCharles.Forsyth		Entity( "&#RS;",	'\n' ),
2170e96539fSCharles.Forsyth		Entity( "&#RE;",	'\r' ),
2180e96539fSCharles.Forsyth		Entity( "&quot;",	'"' ),
2190e96539fSCharles.Forsyth		Entity( "&amp;",	'&' ),
2200e96539fSCharles.Forsyth		Entity( "&lt;",	'<' ),
2210e96539fSCharles.Forsyth		Entity( "&gt;",	'>' ),
2220e96539fSCharles.Forsyth
2230e96539fSCharles.Forsyth		Entity( "CAP-DELTA",	'Δ' ),
2240e96539fSCharles.Forsyth		Entity( "ALPHA",	'α' ),
2250e96539fSCharles.Forsyth		Entity( "BETA",	'β' ),
2260e96539fSCharles.Forsyth		Entity( "DELTA",	'δ' ),
2270e96539fSCharles.Forsyth		Entity( "EPSILON",	'ε' ),
2280e96539fSCharles.Forsyth		Entity( "THETA",	'θ' ),
2290e96539fSCharles.Forsyth		Entity( "MU",		'μ' ),
2300e96539fSCharles.Forsyth		Entity( "PI",		'π' ),
2310e96539fSCharles.Forsyth		Entity( "TAU",	'τ' ),
2320e96539fSCharles.Forsyth		Entity( "CHI",	'χ' ),
2330e96539fSCharles.Forsyth
2340e96539fSCharles.Forsyth		Entity( "<-",		'←' ),
2350e96539fSCharles.Forsyth		Entity( "^",		'↑' ),
2360e96539fSCharles.Forsyth		Entity( "->",		'→' ),
2370e96539fSCharles.Forsyth		Entity( "v",		'↓' ),
2380e96539fSCharles.Forsyth		Entity( "!=",		'≠' ),
2390e96539fSCharles.Forsyth		Entity( "<=",		'≤' ),
2400e96539fSCharles.Forsyth		Entity( nil, 0 ),
2410e96539fSCharles.Forsyth};
2420e96539fSCharles.Forsyth
2430e96539fSCharles.Forsyth
2440e96539fSCharles.ForsythHit: adt {
2450e96539fSCharles.Forsyth	glob: string;
2460e96539fSCharles.Forsyth	chap: string;
2470e96539fSCharles.Forsyth	mtype: string;
2480e96539fSCharles.Forsyth	page: string;
2490e96539fSCharles.Forsyth};
2500e96539fSCharles.Forsyth
2510e96539fSCharles.ForsythLnone, Lordered, Lunordered, Ldef, Lother: con iota;	# list types
2520e96539fSCharles.Forsyth
2530e96539fSCharles.ForsythChaps: adt {
2540e96539fSCharles.Forsyth	name: string;
2550e96539fSCharles.Forsyth	primary: int;
2560e96539fSCharles.Forsyth};
2570e96539fSCharles.Forsyth
2580e96539fSCharles.ForsythTypes: adt {
2590e96539fSCharles.Forsyth	name: string;
2600e96539fSCharles.Forsyth	desc: string;
2610e96539fSCharles.Forsyth};
2620e96539fSCharles.Forsyth
2630e96539fSCharles.Forsyth
2640e96539fSCharles.Forsyth# having two separate flags here allows for inclusion of old-style formatted pages
2650e96539fSCharles.Forsyth# under a new-style three-level tree
2660e96539fSCharles.ForsythOldstyle: adt {
2670e96539fSCharles.Forsyth	names: int;	# two-level directory tree?
2680e96539fSCharles.Forsyth	fmt: int;		# old internal formats: e.g., "B" font means "L"; name in .TH in all caps
2690e96539fSCharles.Forsyth};
2700e96539fSCharles.Forsyth
2710e96539fSCharles.ForsythHref: adt {
2720e96539fSCharles.Forsyth	title: string;
2730e96539fSCharles.Forsyth	chap: string;
2740e96539fSCharles.Forsyth	mtype: string;
2750e96539fSCharles.Forsyth	man: string;
2760e96539fSCharles.Forsyth};
2770e96539fSCharles.Forsyth
2780e96539fSCharles.Forsyth# per-thread global data
2790e96539fSCharles.ForsythGlobal: adt {
2800e96539fSCharles.Forsyth	bufio: Bufio;
2810e96539fSCharles.Forsyth	bin: ref Bufio->Iobuf;
2820e96539fSCharles.Forsyth	bout: ref Bufio->Iobuf;
2830e96539fSCharles.Forsyth	topname: string;		# name of the top level categories in the manual
2840e96539fSCharles.Forsyth	chaps: array of Chaps;	# names of top-level partitions of this manual
2850e96539fSCharles.Forsyth	types: array of Types;	# names of second-level partitions
2860e96539fSCharles.Forsyth	oldstyle: Oldstyle;
2870e96539fSCharles.Forsyth	mantitle: string;
2880e96539fSCharles.Forsyth	mandir: string;
2890e96539fSCharles.Forsyth	thisone: Hit;		# man page we're displaying
2900e96539fSCharles.Forsyth	mtime: int;			# last modification time of thisone
2910e96539fSCharles.Forsyth	href: Href;			# hrefs of components of this man page
2920e96539fSCharles.Forsyth	hits: array of Hit;
2930e96539fSCharles.Forsyth	nhits: int;
2940e96539fSCharles.Forsyth	list_type: int;
2950e96539fSCharles.Forsyth	pm: string;			# proprietary marking
2960e96539fSCharles.Forsyth	def_goobie: string;	# deferred goobie
2970e96539fSCharles.Forsyth	sop: int;			# output at start of paragraph?
2980e96539fSCharles.Forsyth	sol: int;			# input at start of line?
2990e96539fSCharles.Forsyth	broken: int;		# output at a break?
3000e96539fSCharles.Forsyth	fill: int;			# in fill mode?
3010e96539fSCharles.Forsyth 	pre: int;			# in PRE block?
3020e96539fSCharles.Forsyth	example: int;		# an example active?
3030e96539fSCharles.Forsyth	ipd: int;			# emit inter-paragraph distance?
3040e96539fSCharles.Forsyth	indents: int;
3050e96539fSCharles.Forsyth	hangingdt: int;
3060e96539fSCharles.Forsyth	curfont: string;		# current font
3070e96539fSCharles.Forsyth	prevfont: string;		# previous font
3080e96539fSCharles.Forsyth	lastc: int;			# previous char from input scanner
3090e96539fSCharles.Forsyth	def_sm: int;		# amount of deferred "make smaller" request
3100e96539fSCharles.Forsyth
3110e96539fSCharles.Forsyth	mk_href_chap: fn(g: self ref Global, chap: string);
3120e96539fSCharles.Forsyth	mk_href_man: fn(g: self ref Global, man: string, oldstyle: int);
3130e96539fSCharles.Forsyth	mk_href_mtype: fn(g: self ref Global, chap, mtype: string);
3140e96539fSCharles.Forsyth	dobreak: fn(g: self ref Global);
3150e96539fSCharles.Forsyth	print: fn(g: self ref Global, s: string);
3160e96539fSCharles.Forsyth	softbr: fn(g: self ref Global): string;
3170e96539fSCharles.Forsyth	softp: fn(g: self ref Global): string;
3180e96539fSCharles.Forsyth};
3190e96539fSCharles.Forsyth
32030dcb98cSCharles.Forsythheader := "<HTML><HEAD>";
321*7cdb1d14SCharles.Forsythinitial := "";
32230dcb98cSCharles.Forsythtrailer := "</BODY></HTML>";
3230e96539fSCharles.Forsyth
3240e96539fSCharles.Forsythusage()
3250e96539fSCharles.Forsyth{
326*7cdb1d14SCharles.Forsyth	sys->fprint(stderr, "Usage: man2html [-h header] [-i initialtext] [-t trailer] file [section]\n");
3270e96539fSCharles.Forsyth	raise "fail:usage";
3280e96539fSCharles.Forsyth}
3290e96539fSCharles.Forsyth
3300e96539fSCharles.Forsyth
3310e96539fSCharles.Forsythinit(nil: ref Draw->Context, args: list of string)
3320e96539fSCharles.Forsyth{
3330e96539fSCharles.Forsyth	sys = load Sys Sys->PATH;
3340e96539fSCharles.Forsyth	stderr = sys->fildes(2);
3350e96539fSCharles.Forsyth	str = load String String->PATH;
3360e96539fSCharles.Forsyth	dt = load Daytime Daytime->PATH;
33730dcb98cSCharles.Forsyth	arg := load Arg Arg->PATH;
33830dcb98cSCharles.Forsyth	arg->init(args);
33930dcb98cSCharles.Forsyth	arg->setusage("man2html [-h header] [-t trailer] file [section]");
34030dcb98cSCharles.Forsyth	while((o := arg->opt()) != 0)
34130dcb98cSCharles.Forsyth		case o {
34230dcb98cSCharles.Forsyth		'h' =>	header = arg->earg();
34330dcb98cSCharles.Forsyth		't' =>	trailer = arg->earg();
34430dcb98cSCharles.Forsyth		* =>	arg->usage();
34530dcb98cSCharles.Forsyth		}
34630dcb98cSCharles.Forsyth	args = arg->argv();
3470e96539fSCharles.Forsyth	if(args == nil)
34830dcb98cSCharles.Forsyth		arg->usage();
34930dcb98cSCharles.Forsyth	arg = nil;
35030dcb98cSCharles.Forsyth	g := Global_init();
3510e96539fSCharles.Forsyth	page := hd args;
3520e96539fSCharles.Forsyth	args = tl args;
3530e96539fSCharles.Forsyth	section := "1";
3540e96539fSCharles.Forsyth	if(args != nil)
3550e96539fSCharles.Forsyth		section = hd args;
3560e96539fSCharles.Forsyth	hit := Hit ("", "man", section, page);
3570e96539fSCharles.Forsyth	domanpage(g, hit);
35830dcb98cSCharles.Forsyth	g.print(trailer+"\n");
3590e96539fSCharles.Forsyth	g.bufio->g.bout.flush();
3600e96539fSCharles.Forsyth}
3610e96539fSCharles.Forsyth
3620e96539fSCharles.Forsyth# remove markup from a string
3630e96539fSCharles.Forsyth# doesn't handle nested/quoted delimiters
3640e96539fSCharles.Forsythdemark(s: string): string
3650e96539fSCharles.Forsyth{
3660e96539fSCharles.Forsyth	t: string;
3670e96539fSCharles.Forsyth	clean := true;
3680e96539fSCharles.Forsyth	for (i := 0; i < len s; i++) {
3690e96539fSCharles.Forsyth		case s[i] {
3700e96539fSCharles.Forsyth		'<' =>
3710e96539fSCharles.Forsyth			clean = false;
3720e96539fSCharles.Forsyth		'>' =>
3730e96539fSCharles.Forsyth			clean = true;
3740e96539fSCharles.Forsyth		* =>
3750e96539fSCharles.Forsyth			if (clean)
3760e96539fSCharles.Forsyth				t[len t] = s[i];
3770e96539fSCharles.Forsyth		}
3780e96539fSCharles.Forsyth	}
3790e96539fSCharles.Forsyth	return t;
3800e96539fSCharles.Forsyth}
3810e96539fSCharles.Forsyth
3820e96539fSCharles.Forsyth
3830e96539fSCharles.Forsyth#
3840e96539fSCharles.Forsyth#  Convert an individual man page to HTML and output.
3850e96539fSCharles.Forsyth#
3860e96539fSCharles.Forsythdomanpage(g: ref Global, man: Hit)
3870e96539fSCharles.Forsyth{
3880e96539fSCharles.Forsyth	file := man.page;
3890e96539fSCharles.Forsyth	g.bin = g.bufio->open(file, Bufio->OREAD);
3900e96539fSCharles.Forsyth	g.bout = g.bufio->fopen(sys->fildes(1), Bufio->OWRITE);
3910e96539fSCharles.Forsyth	if (g.bin == nil) {
3920e96539fSCharles.Forsyth		fprint(stderr, "Cannot open %s: %r\n", file);
3930e96539fSCharles.Forsyth		return;
3940e96539fSCharles.Forsyth	}
3950e96539fSCharles.Forsyth	(err, info) := sys->fstat(g.bin.fd);
3960e96539fSCharles.Forsyth	if (! err) {
3970e96539fSCharles.Forsyth		g.mtime = info.mtime;
3980e96539fSCharles.Forsyth	}
3990e96539fSCharles.Forsyth	g.thisone = man;
4000e96539fSCharles.Forsyth	while ((p := getnext(g)) != nil) {
4010e96539fSCharles.Forsyth		c := p[0];
4020e96539fSCharles.Forsyth		if (c == '.' && g.sol) {
4030e96539fSCharles.Forsyth			if (g.pre) {
4040e96539fSCharles.Forsyth				g.print("</PRE>");
4050e96539fSCharles.Forsyth				g.pre = false;
4060e96539fSCharles.Forsyth			}
4070e96539fSCharles.Forsyth			dogoobie(g, false);
4080e96539fSCharles.Forsyth			dohangingdt(g);
4090e96539fSCharles.Forsyth		} else if (g.def_goobie != nil || g.def_sm != 0) {
4100e96539fSCharles.Forsyth			g.bufio->g.bin.ungetc();
4110e96539fSCharles.Forsyth			dogoobie(g, true);
4120e96539fSCharles.Forsyth		} else if (c == '\n') {
4130e96539fSCharles.Forsyth			g.print(p);
4140e96539fSCharles.Forsyth			dohangingdt(g);
4150e96539fSCharles.Forsyth		} else
4160e96539fSCharles.Forsyth			g.print(p);
4170e96539fSCharles.Forsyth	}
4180e96539fSCharles.Forsyth	if (g.pm != nil) {
4190e96539fSCharles.Forsyth		g.print("<BR><BR><BR><FONT SIZE=-2><CENTER>\n");
4200e96539fSCharles.Forsyth		g.print(g.pm);
4210e96539fSCharles.Forsyth		g.print("<BR></CENTER></FONT>\n");
4220e96539fSCharles.Forsyth	}
4230e96539fSCharles.Forsyth	closeall(g, 0);
4240e96539fSCharles.Forsyth	rev(g, g.bin);
4250e96539fSCharles.Forsyth}
4260e96539fSCharles.Forsyth
4270e96539fSCharles.Forsythdogoobie(g: ref Global, deferred: int)
4280e96539fSCharles.Forsyth{
4290e96539fSCharles.Forsyth	# read line, translate special chars
43079aa5773SCharles.Forsyth	line := getline(g);
43179aa5773SCharles.Forsyth	if (line == nil || line == "\n")
4320e96539fSCharles.Forsyth		return;
4330e96539fSCharles.Forsyth
4340e96539fSCharles.Forsyth	# parse into arguments
43579aa5773SCharles.Forsyth	token: string;
4360e96539fSCharles.Forsyth	argl, rargl: list of string;	# create reversed version, then invert
43779aa5773SCharles.Forsyth	while ((line = str->drop(line, " \t\n")) != nil)
4380e96539fSCharles.Forsyth		if (line[0] == '"') {
4390e96539fSCharles.Forsyth			(token, line) = split(line[1:], '"');
4400e96539fSCharles.Forsyth			rargl = token :: rargl;
4410e96539fSCharles.Forsyth		} else {
4420e96539fSCharles.Forsyth			(token, line) = str->splitl(line, " \t");
4430e96539fSCharles.Forsyth			rargl = token :: rargl;
4440e96539fSCharles.Forsyth		}
4450e96539fSCharles.Forsyth
4460e96539fSCharles.Forsyth	if (rargl == nil && !deferred)
4470e96539fSCharles.Forsyth		return;
4480e96539fSCharles.Forsyth	for ( ; rargl != nil; rargl = tl rargl)
4490e96539fSCharles.Forsyth		argl = hd rargl :: argl;
4500e96539fSCharles.Forsyth
4510e96539fSCharles.Forsyth	def_sm := g.def_sm;
4520e96539fSCharles.Forsyth	if (deferred && def_sm > 0) {
4530e96539fSCharles.Forsyth		g.print(sprint("<FONT SIZE=-%d>", def_sm));
4540e96539fSCharles.Forsyth		if (g.def_goobie == nil)
4550e96539fSCharles.Forsyth			argl = "dS" :: argl;	# dS is our own local creation
4560e96539fSCharles.Forsyth	}
4570e96539fSCharles.Forsyth
4580e96539fSCharles.Forsyth	subgoobie(g, argl);
4590e96539fSCharles.Forsyth
4600e96539fSCharles.Forsyth	if (deferred && def_sm > 0) {
4610e96539fSCharles.Forsyth		g.def_sm = 0;
4620e96539fSCharles.Forsyth		g.print("</FONT>");
4630e96539fSCharles.Forsyth	}
4640e96539fSCharles.Forsyth}
4650e96539fSCharles.Forsyth
4660e96539fSCharles.Forsythsubgoobie(g: ref Global, argl: list of string)
4670e96539fSCharles.Forsyth{
4680e96539fSCharles.Forsyth	if (g.def_goobie != nil) {
4690e96539fSCharles.Forsyth		argl = g.def_goobie :: argl;
4700e96539fSCharles.Forsyth		g.def_goobie = nil;
4710e96539fSCharles.Forsyth		if (tl argl == nil)
4720e96539fSCharles.Forsyth			return;
4730e96539fSCharles.Forsyth	}
4740e96539fSCharles.Forsyth
4750e96539fSCharles.Forsyth	# the command part is at most two characters, but may be concatenated with the first arg
4760e96539fSCharles.Forsyth	cmd := hd argl;
4770e96539fSCharles.Forsyth	argl = tl argl;
4780e96539fSCharles.Forsyth	if (len cmd > 2) {
4790e96539fSCharles.Forsyth		cmd = cmd[0:2];
4800e96539fSCharles.Forsyth		argl =  cmd[2:] :: argl;
4810e96539fSCharles.Forsyth	}
4820e96539fSCharles.Forsyth
4830e96539fSCharles.Forsyth	case cmd {
4840e96539fSCharles.Forsyth
4850e96539fSCharles.Forsyth	"B" or "I" or "L" or "R" =>
4860e96539fSCharles.Forsyth		font(g, cmd, argl);		# "R" macro implicitly generated by deferred R* macros
4870e96539fSCharles.Forsyth
4880e96539fSCharles.Forsyth	"BI" or "BL" or "BR" or
4890e96539fSCharles.Forsyth	"IB" or "IL" or
4900e96539fSCharles.Forsyth	"LB" or "LI" or
4910e96539fSCharles.Forsyth	"RB" or "RI" or "RL" =>
4920e96539fSCharles.Forsyth		altfont(g, cmd[0:1], cmd[1:2], argl, true);
4930e96539fSCharles.Forsyth
4940e96539fSCharles.Forsyth	"IR" or "LR" =>
4950e96539fSCharles.Forsyth		anchor(g, cmd[0:1], cmd[1:2], argl);		# includes man page refs ("IR" is old style, "LR" is new)
4960e96539fSCharles.Forsyth
4970e96539fSCharles.Forsyth	"dS" =>
4980e96539fSCharles.Forsyth		printargs(g, argl);
4990e96539fSCharles.Forsyth		g.print("\n");
5000e96539fSCharles.Forsyth
5010e96539fSCharles.Forsyth	"1C" or "2C" or "DT" or "TF" =>	 # ignore these
5020e96539fSCharles.Forsyth		return;
5030e96539fSCharles.Forsyth
50479aa5773SCharles.Forsyth	"ig" =>
50579aa5773SCharles.Forsyth		while ((line := getline(g)) != nil){
50679aa5773SCharles.Forsyth			if(len line > 1 && line[0:2] == "..")
50779aa5773SCharles.Forsyth				break;
50879aa5773SCharles.Forsyth		}
50979aa5773SCharles.Forsyth		return;
51079aa5773SCharles.Forsyth
5110e96539fSCharles.Forsyth	"P" or "PP" or "LP" =>
5120e96539fSCharles.Forsyth			g_PP(g);
5130e96539fSCharles.Forsyth
5140e96539fSCharles.Forsyth	"EE" =>	g_EE(g);
5150e96539fSCharles.Forsyth	"EX" =>	g_EX(g);
5160e96539fSCharles.Forsyth	"HP" =>	g_HP_TP(g, 1);
5170e96539fSCharles.Forsyth	"IP" =>	g_IP(g, argl);
5180e96539fSCharles.Forsyth	"PD" =>	g_PD(g, argl);
5190e96539fSCharles.Forsyth	"PM" =>	g_PM(g, argl);
5200e96539fSCharles.Forsyth	"RE" =>	g_RE(g);
5210e96539fSCharles.Forsyth	"RS" =>	g_RS(g);
5220e96539fSCharles.Forsyth	"SH" =>	g_SH(g, argl);
5230e96539fSCharles.Forsyth	"SM" =>	g_SM(g, argl);
5240e96539fSCharles.Forsyth	"SS" =>	g_SS(g, argl);
5250e96539fSCharles.Forsyth	"TH" =>	g_TH(g, argl);
5260e96539fSCharles.Forsyth	"TP" =>	g_HP_TP(g, 3);
5270e96539fSCharles.Forsyth
5280e96539fSCharles.Forsyth	"br" =>	g_br(g);
5290e96539fSCharles.Forsyth	"sp" =>	g_sp(g, argl);
5300e96539fSCharles.Forsyth	"ti" =>	g_br(g);
5310e96539fSCharles.Forsyth	"nf" =>	g_nf(g);
5320e96539fSCharles.Forsyth	"fi" =>	g_fi(g);
5330e96539fSCharles.Forsyth	"ft" =>	g_ft(g, argl);
5340e96539fSCharles.Forsyth
5350e96539fSCharles.Forsyth	* =>		return;		# ignore unrecognized commands
5360e96539fSCharles.Forsyth	}
5370e96539fSCharles.Forsyth
5380e96539fSCharles.Forsyth}
5390e96539fSCharles.Forsyth
5400e96539fSCharles.Forsythg_br(g: ref Global)
5410e96539fSCharles.Forsyth{
5420e96539fSCharles.Forsyth	if (g.hangingdt != 0) {
5430e96539fSCharles.Forsyth		g.print("<DD>");
5440e96539fSCharles.Forsyth		g.hangingdt = 0;
5450e96539fSCharles.Forsyth	} else if (g.fill && ! g.broken)
5460e96539fSCharles.Forsyth		g.print("<BR>\n");
5470e96539fSCharles.Forsyth	g.broken = true;
5480e96539fSCharles.Forsyth}
5490e96539fSCharles.Forsyth
5500e96539fSCharles.Forsythg_EE(g: ref Global)
5510e96539fSCharles.Forsyth{
5520e96539fSCharles.Forsyth	g.print("</PRE>\n");
5530e96539fSCharles.Forsyth	g.fill = true;
5540e96539fSCharles.Forsyth	g.broken = true;
5550e96539fSCharles.Forsyth	g.example = false;
5560e96539fSCharles.Forsyth}
5570e96539fSCharles.Forsyth
5580e96539fSCharles.Forsythg_EX(g: ref Global)
5590e96539fSCharles.Forsyth{
5600e96539fSCharles.Forsyth	g.print("<PRE>");
5610e96539fSCharles.Forsyth	if (! g.broken)
5620e96539fSCharles.Forsyth		g.print("\n");
5630e96539fSCharles.Forsyth	g.sop = true;
5640e96539fSCharles.Forsyth	g.fill = false;
5650e96539fSCharles.Forsyth	g.broken = true;
5660e96539fSCharles.Forsyth	g.example = true;
5670e96539fSCharles.Forsyth}
5680e96539fSCharles.Forsyth
5690e96539fSCharles.Forsythg_fi(g: ref Global)
5700e96539fSCharles.Forsyth{
5710e96539fSCharles.Forsyth	if (g.fill)
5720e96539fSCharles.Forsyth		return;
5730e96539fSCharles.Forsyth	g.fill = true;
5740e96539fSCharles.Forsyth	g.print("<P style=\"display: inline; white-space: normal\">\n");
5750e96539fSCharles.Forsyth	g.broken = true;
5760e96539fSCharles.Forsyth	g.sop = true;
5770e96539fSCharles.Forsyth}
5780e96539fSCharles.Forsyth
5790e96539fSCharles.Forsythg_ft(g: ref Global, argl: list of string)
5800e96539fSCharles.Forsyth{
5810e96539fSCharles.Forsyth	font: string;
5820e96539fSCharles.Forsyth	arg: string;
5830e96539fSCharles.Forsyth
5840e96539fSCharles.Forsyth	if (argl == nil)
5850e96539fSCharles.Forsyth		arg = "P";
5860e96539fSCharles.Forsyth	else
5870e96539fSCharles.Forsyth		arg = hd argl;
5880e96539fSCharles.Forsyth
5890e96539fSCharles.Forsyth	if (g.curfont != nil)
5900e96539fSCharles.Forsyth		g.print(sprint("</%s>", g.curfont));
5910e96539fSCharles.Forsyth
5920e96539fSCharles.Forsyth	case arg {
5930e96539fSCharles.Forsyth	"2" or "I" =>
5940e96539fSCharles.Forsyth		font = "I";
5950e96539fSCharles.Forsyth	"3" or "B" =>
5960e96539fSCharles.Forsyth		font = "B";
5970e96539fSCharles.Forsyth	"5" or "L" =>
5980e96539fSCharles.Forsyth		font = "TT";
5990e96539fSCharles.Forsyth	"P" =>
6000e96539fSCharles.Forsyth		font = g.prevfont;
6010e96539fSCharles.Forsyth	* =>
6020e96539fSCharles.Forsyth		font = nil;
6030e96539fSCharles.Forsyth	}
6040e96539fSCharles.Forsyth	g.prevfont = g.curfont;
6050e96539fSCharles.Forsyth	g.curfont = font;
6060e96539fSCharles.Forsyth	if (g.curfont != nil)
6070e96539fSCharles.Forsyth		if (g.fill)
6080e96539fSCharles.Forsyth			g.print(sprint("<%s>", g.curfont));
6090e96539fSCharles.Forsyth		else
6100e96539fSCharles.Forsyth			g.print(sprint("<%s style=\"white-space: pre\">", g.curfont));
6110e96539fSCharles.Forsyth}
6120e96539fSCharles.Forsyth
6130e96539fSCharles.Forsyth# level == 1 is a .HP; level == 3 is a .TP
6140e96539fSCharles.Forsythg_HP_TP(g: ref Global, level: int)
6150e96539fSCharles.Forsyth{
6160e96539fSCharles.Forsyth	case g.list_type {
6170e96539fSCharles.Forsyth	Ldef =>
6180e96539fSCharles.Forsyth		if (g.hangingdt != 0)
6190e96539fSCharles.Forsyth			g.print("<DD>");
6200e96539fSCharles.Forsyth		g.print(g.softbr() + "<DT>");
6210e96539fSCharles.Forsyth	* =>
6220e96539fSCharles.Forsyth		closel(g);
6230e96539fSCharles.Forsyth		g.list_type = Ldef;
6240e96539fSCharles.Forsyth		g.print("<DL compact>\n" + g.softbr() + "<DT>");
6250e96539fSCharles.Forsyth	}
6260e96539fSCharles.Forsyth	g.hangingdt = level;
6270e96539fSCharles.Forsyth	g.broken = true;
6280e96539fSCharles.Forsyth}
6290e96539fSCharles.Forsyth
6300e96539fSCharles.Forsythg_IP(g: ref Global, argl: list of string)
6310e96539fSCharles.Forsyth{
6320e96539fSCharles.Forsyth	case g.list_type {
6330e96539fSCharles.Forsyth
6340e96539fSCharles.Forsyth	Lordered or Lunordered or Lother =>
6350e96539fSCharles.Forsyth		;	# continue with an existing list
6360e96539fSCharles.Forsyth
6370e96539fSCharles.Forsyth	* =>
6380e96539fSCharles.Forsyth		# figure out the type of a new list and start it
6390e96539fSCharles.Forsyth		closel(g);
6400e96539fSCharles.Forsyth		arg := "";
6410e96539fSCharles.Forsyth		if (argl != nil)
6420e96539fSCharles.Forsyth			arg = hd argl;
6430e96539fSCharles.Forsyth		case arg {
6440e96539fSCharles.Forsyth			"1" or "i" or "I" or "a" or "A" =>
6450e96539fSCharles.Forsyth				g.list_type = Lordered;
6460e96539fSCharles.Forsyth				g.print(sprint("<OL type=%s>\n", arg));
6470e96539fSCharles.Forsyth			"*" or "•" or "&#8226;" =>
6480e96539fSCharles.Forsyth				g.list_type = Lunordered;
6490e96539fSCharles.Forsyth				g.print("<UL type=disc>\n");
6500e96539fSCharles.Forsyth			"○" or "&#9675;"=>
6510e96539fSCharles.Forsyth				g.list_type = Lunordered;
6520e96539fSCharles.Forsyth				g.print("<UL type=circle>\n");
6530e96539fSCharles.Forsyth			"□" or "&#9633;" =>
6540e96539fSCharles.Forsyth				g.list_type = Lunordered;
6550e96539fSCharles.Forsyth				g.print("<UL type=square>\n");
6560e96539fSCharles.Forsyth			* =>
6570e96539fSCharles.Forsyth				g.list_type = Lother;
6580e96539fSCharles.Forsyth				g.print("<DL compact>\n");
6590e96539fSCharles.Forsyth			}
6600e96539fSCharles.Forsyth	}
6610e96539fSCharles.Forsyth
6620e96539fSCharles.Forsyth	# actually do this list item
6630e96539fSCharles.Forsyth	case g.list_type {
6640e96539fSCharles.Forsyth	Lother =>
6650e96539fSCharles.Forsyth		g.print(g.softp());	# make sure there's space before each list item
6660e96539fSCharles.Forsyth		if (argl != nil) {
6670e96539fSCharles.Forsyth			g.print("<DT>");
6680e96539fSCharles.Forsyth			printargs(g, argl);
6690e96539fSCharles.Forsyth		}
6700e96539fSCharles.Forsyth		g.print("\n<DD>");
6710e96539fSCharles.Forsyth
6720e96539fSCharles.Forsyth	Lordered or Lunordered =>
6730e96539fSCharles.Forsyth		g.print(g.softp() + "<LI>");
6740e96539fSCharles.Forsyth	}
6750e96539fSCharles.Forsyth	g.broken = true;
6760e96539fSCharles.Forsyth}
6770e96539fSCharles.Forsyth
6780e96539fSCharles.Forsythg_nf(g: ref Global)
6790e96539fSCharles.Forsyth{
6800e96539fSCharles.Forsyth	if (! g.fill)
6810e96539fSCharles.Forsyth		return;
6820e96539fSCharles.Forsyth	g.fill = false;
6830e96539fSCharles.Forsyth	g.print("<PRE>\n");
6840e96539fSCharles.Forsyth	g.broken = true;
6850e96539fSCharles.Forsyth	g.sop = true;
6860e96539fSCharles.Forsyth	g.pre = true;
6870e96539fSCharles.Forsyth}
6880e96539fSCharles.Forsyth
6890e96539fSCharles.Forsythg_PD(g: ref Global, argl: list of string)
6900e96539fSCharles.Forsyth{
6910e96539fSCharles.Forsyth	if (len argl == 1 && hd argl == "0")
6920e96539fSCharles.Forsyth		g.ipd = false;
6930e96539fSCharles.Forsyth	else
6940e96539fSCharles.Forsyth		g.ipd = true;
6950e96539fSCharles.Forsyth}
6960e96539fSCharles.Forsyth
6970e96539fSCharles.Forsythg_PM(g: ref Global, argl: list of string)
6980e96539fSCharles.Forsyth{
6990e96539fSCharles.Forsyth	code := "P";
7000e96539fSCharles.Forsyth	if (argl != nil)
7010e96539fSCharles.Forsyth		code = hd argl;
7020e96539fSCharles.Forsyth	case code {
7030e96539fSCharles.Forsyth	* =>		# includes "1" and "P"
7040e96539fSCharles.Forsyth		g.pm = "<B>Lucent Technologies - Proprietary</B>\n" +
7050e96539fSCharles.Forsyth			"<BR>Use pursuant to Company Instructions.\n";
7060e96539fSCharles.Forsyth	"2" or "RS" =>
7070e96539fSCharles.Forsyth		g.pm = "<B>Lucent Technologies - Proprietary (Restricted)</B>\n" +
7080e96539fSCharles.Forsyth			"<BR>Solely for authorized persons having a need to know\n" +
7090e96539fSCharles.Forsyth			"<BR>pursuant to Company Instructions.\n";
7100e96539fSCharles.Forsyth	"3" or "RG" =>
7110e96539fSCharles.Forsyth		g.pm = "<B>Lucent Technologies - Proprietary (Registered)</B>\n" +
7120e96539fSCharles.Forsyth			"<BR>Solely for authorized persons having a need to know\n" +
7130e96539fSCharles.Forsyth			"<BR>and subject to cover sheet instructions.\n";
7140e96539fSCharles.Forsyth	"4" or "CP" =>
7150e96539fSCharles.Forsyth		g.pm = "SEE PROPRIETARY NOTICE ON COVER PAGE\n";
7160e96539fSCharles.Forsyth	"5" or "CR" =>
7170e96539fSCharles.Forsyth		g.pm = "Copyright xxxx Lucent Technologies\n" +	# should fill in the year from the date register
7180e96539fSCharles.Forsyth			"<BR>All Rights Reserved.\n";
7190e96539fSCharles.Forsyth	"6" or "UW" =>
7200e96539fSCharles.Forsyth		g.pm = "THIS DOCUMENT CONTAINS PROPRIETARY INFORMATION OF\n" +
7210e96539fSCharles.Forsyth			"<BR>LUCENT TECHNOLOGIES INC. AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN\n" +
7220e96539fSCharles.Forsyth			"<BR>ACCORDANCE WITH APPLICABLE AGREEMENTS.\n" +
7230e96539fSCharles.Forsyth			"<BR>Unpublished & Not for Publication\n";
7240e96539fSCharles.Forsyth	}
7250e96539fSCharles.Forsyth}
7260e96539fSCharles.Forsyth
7270e96539fSCharles.Forsythg_PP(g: ref Global)
7280e96539fSCharles.Forsyth{
7290e96539fSCharles.Forsyth	closel(g);
7300e96539fSCharles.Forsyth	reset_font(g);
7310e96539fSCharles.Forsyth	p := g.softp();
7320e96539fSCharles.Forsyth	if (p != nil)
7330e96539fSCharles.Forsyth		g.print(p);
7340e96539fSCharles.Forsyth	g.sop = true;
7350e96539fSCharles.Forsyth	g.broken = true;
7360e96539fSCharles.Forsyth}
7370e96539fSCharles.Forsyth
7380e96539fSCharles.Forsythg_RE(g: ref Global)
7390e96539fSCharles.Forsyth{
7400e96539fSCharles.Forsyth	g.print("</DL>\n");
7410e96539fSCharles.Forsyth	g.indents--;
7420e96539fSCharles.Forsyth	g.broken = true;
7430e96539fSCharles.Forsyth}
7440e96539fSCharles.Forsyth
7450e96539fSCharles.Forsythg_RS(g: ref Global)
7460e96539fSCharles.Forsyth{
7470e96539fSCharles.Forsyth	g.print("<DL>\n<DT><DD>");
7480e96539fSCharles.Forsyth	g.indents++;
7490e96539fSCharles.Forsyth	g.broken = true;
7500e96539fSCharles.Forsyth}
7510e96539fSCharles.Forsyth
7520e96539fSCharles.Forsythg_SH(g: ref Global, argl: list of string)
7530e96539fSCharles.Forsyth{
7540e96539fSCharles.Forsyth	closeall(g, 1);		# .SH is top-level list item
7550e96539fSCharles.Forsyth	if (g.example)
7560e96539fSCharles.Forsyth		g_EE(g);
757*7cdb1d14SCharles.Forsyth	g_fi(g);
7580e96539fSCharles.Forsyth	if (g.fill && ! g.sop)
7590e96539fSCharles.Forsyth		g.print("<P>");
7600e96539fSCharles.Forsyth	g.print("<DT><H4>");
7610e96539fSCharles.Forsyth	printargs(g, argl);
7620e96539fSCharles.Forsyth	g.print("</H4>\n");
7630e96539fSCharles.Forsyth	g.print("<DD>\n");
7640e96539fSCharles.Forsyth	g.sop = true;
7650e96539fSCharles.Forsyth	g.broken = true;
7660e96539fSCharles.Forsyth}
7670e96539fSCharles.Forsyth
7680e96539fSCharles.Forsythg_SM(g: ref Global, argl: list of string)
7690e96539fSCharles.Forsyth{
7700e96539fSCharles.Forsyth	g.def_sm++;		# can't use def_goobie, lest we collide with a deferred font macro
7710e96539fSCharles.Forsyth	if (argl == nil)
7720e96539fSCharles.Forsyth		return;
7730e96539fSCharles.Forsyth	g.print(sprint("<FONT SIZE=-%d>", g.def_sm));
7740e96539fSCharles.Forsyth	printargs(g, argl);
7750e96539fSCharles.Forsyth	g.print("</FONT>\n");
7760e96539fSCharles.Forsyth	g.def_sm = 0;
7770e96539fSCharles.Forsyth}
7780e96539fSCharles.Forsyth
7790e96539fSCharles.Forsythg_sp(g: ref Global, argl: list of string)
7800e96539fSCharles.Forsyth{
7810e96539fSCharles.Forsyth	if (g.sop && g.fill)
7820e96539fSCharles.Forsyth		return;
7830e96539fSCharles.Forsyth	count := 1;
7840e96539fSCharles.Forsyth	if (argl != nil) {
7850e96539fSCharles.Forsyth		rcount := real hd argl;
7860e96539fSCharles.Forsyth		count = int rcount;	# may be 0 (e.g., ".sp .5")
7870e96539fSCharles.Forsyth		if (count == 0 && rcount > 0.0)
7880e96539fSCharles.Forsyth			count = 1;		# force whitespace for fractional lines
7890e96539fSCharles.Forsyth	}
7900e96539fSCharles.Forsyth	g.dobreak();
7910e96539fSCharles.Forsyth	for (i := 0; i < count; i++)
7920e96539fSCharles.Forsyth		g.print("&nbsp;<BR>\n");
7930e96539fSCharles.Forsyth	g.broken = true;
7940e96539fSCharles.Forsyth	g.sop = count > 0;
7950e96539fSCharles.Forsyth}
7960e96539fSCharles.Forsyth
7970e96539fSCharles.Forsythg_SS(g: ref Global, argl: list of string)
7980e96539fSCharles.Forsyth{
7990e96539fSCharles.Forsyth	closeall(g, 1);
8000e96539fSCharles.Forsyth	g.indents++;
8010e96539fSCharles.Forsyth	g.print(g.softp() + "<DL><DT><FONT SIZE=3><B>");
8020e96539fSCharles.Forsyth	printargs(g, argl);
8030e96539fSCharles.Forsyth	g.print("</B></FONT>\n");
8040e96539fSCharles.Forsyth	g.print("<DD>\n");
8050e96539fSCharles.Forsyth	g.sop = true;
8060e96539fSCharles.Forsyth	g.broken = true;
8070e96539fSCharles.Forsyth}
8080e96539fSCharles.Forsyth
8090e96539fSCharles.Forsythg_TH(g: ref Global, argl: list of string)
8100e96539fSCharles.Forsyth{
8110e96539fSCharles.Forsyth	if (g.oldstyle.names && len argl > 2)
8120e96539fSCharles.Forsyth		argl = hd argl :: hd tl argl :: nil;	# ignore extra .TH args on pages in oldstyle trees
8130e96539fSCharles.Forsyth	case len argl {
8140e96539fSCharles.Forsyth	0 =>
8150e96539fSCharles.Forsyth		g.oldstyle.fmt = true;
8160e96539fSCharles.Forsyth		title(g, sprint("%s", g.href.title), false);
8170e96539fSCharles.Forsyth	1 =>
8180e96539fSCharles.Forsyth		g.oldstyle.fmt = true;
8190e96539fSCharles.Forsyth		title(g, sprint("%s", hd argl), false);	# any pages use this form?
8200e96539fSCharles.Forsyth	2 =>
8210e96539fSCharles.Forsyth		g.oldstyle.fmt = true;
8220e96539fSCharles.Forsyth		g.thisone.page = hd argl;
8230e96539fSCharles.Forsyth		g.thisone.mtype = hd tl argl;
8240e96539fSCharles.Forsyth		g.mk_href_man(hd argl, true);
8250e96539fSCharles.Forsyth		g.mk_href_mtype(nil, hd tl argl);
8260e96539fSCharles.Forsyth		title(g, sprint("%s(%s)", g.href.man, g.href.mtype), false);
8270e96539fSCharles.Forsyth	* =>
8280e96539fSCharles.Forsyth		g.oldstyle.fmt = false;
8290e96539fSCharles.Forsyth		chap := hd tl tl argl;
8300e96539fSCharles.Forsyth		g.mk_href_chap(chap);
8310e96539fSCharles.Forsyth		g.mk_href_man(hd argl, false);
8320e96539fSCharles.Forsyth		g.mk_href_mtype(chap, hd tl argl);
8330e96539fSCharles.Forsyth		title(g, sprint("%s/%s/%s(%s)", g.href.title, g.href.chap, g.href.man, g.href.mtype), false);
8340e96539fSCharles.Forsyth	}
8350e96539fSCharles.Forsyth	g.print("[<a href=\"../index.html\">manual index</a>]");
8360e96539fSCharles.Forsyth	g.print("[<a href=\"INDEX.html\">section index</a>]<p>");
8370e96539fSCharles.Forsyth	g.print("<DL>\n");	# whole man page is just one big list
8380e96539fSCharles.Forsyth	g.indents = 1;
8390e96539fSCharles.Forsyth	g.sop = true;
8400e96539fSCharles.Forsyth	g.broken = true;
8410e96539fSCharles.Forsyth}
8420e96539fSCharles.Forsyth
8430e96539fSCharles.Forsythdohangingdt(g: ref Global)
8440e96539fSCharles.Forsyth{
8450e96539fSCharles.Forsyth	case g.hangingdt {
8460e96539fSCharles.Forsyth	3 =>
8470e96539fSCharles.Forsyth		g.hangingdt--;
8480e96539fSCharles.Forsyth	2 =>
8490e96539fSCharles.Forsyth		g.print("<DD>");
8500e96539fSCharles.Forsyth		g.hangingdt = 0;
8510e96539fSCharles.Forsyth		g.broken = true;
8520e96539fSCharles.Forsyth	}
8530e96539fSCharles.Forsyth}
8540e96539fSCharles.Forsyth
8550e96539fSCharles.Forsyth# close a list, if there's one active
8560e96539fSCharles.Forsythclosel(g: ref Global)
8570e96539fSCharles.Forsyth{
8580e96539fSCharles.Forsyth	case g.list_type {
8590e96539fSCharles.Forsyth	Lordered =>
8600e96539fSCharles.Forsyth		g.print("</OL>\n");
8610e96539fSCharles.Forsyth		g.broken = true;
8620e96539fSCharles.Forsyth	Lunordered =>
8630e96539fSCharles.Forsyth		g.print("</UL>\n");
8640e96539fSCharles.Forsyth		g.broken = true;
8650e96539fSCharles.Forsyth	Lother or Ldef =>
8660e96539fSCharles.Forsyth		g.print("</DL>\n");
8670e96539fSCharles.Forsyth		g.broken = true;
8680e96539fSCharles.Forsyth	}
8690e96539fSCharles.Forsyth	g.list_type = Lnone;
8700e96539fSCharles.Forsyth}
8710e96539fSCharles.Forsyth
8720e96539fSCharles.Forsythcloseall(g: ref Global, level: int)
8730e96539fSCharles.Forsyth{
8740e96539fSCharles.Forsyth	closel(g);
8750e96539fSCharles.Forsyth	reset_font(g);
8760e96539fSCharles.Forsyth	while (g.indents > level) {
8770e96539fSCharles.Forsyth		g.indents--;
8780e96539fSCharles.Forsyth		g.print("</DL>\n");
8790e96539fSCharles.Forsyth		g.broken = true;
8800e96539fSCharles.Forsyth	}
8810e96539fSCharles.Forsyth}
8820e96539fSCharles.Forsyth
8830e96539fSCharles.Forsyth#
8840e96539fSCharles.Forsyth# Show last revision date for a file.
8850e96539fSCharles.Forsyth#
8860e96539fSCharles.Forsythrev(g: ref Global, filebuf: ref Bufio->Iobuf)
8870e96539fSCharles.Forsyth{
8880e96539fSCharles.Forsyth	if (g.mtime == 0) {
8890e96539fSCharles.Forsyth		(err, info) := sys->fstat(filebuf.fd);
8900e96539fSCharles.Forsyth		if (! err)
8910e96539fSCharles.Forsyth			g.mtime = info.mtime;
8920e96539fSCharles.Forsyth	}
8930e96539fSCharles.Forsyth	if (g.mtime != 0) {
8940e96539fSCharles.Forsyth		g.print("<P><TABLE width=\"100%\" border=0 cellpadding=10 cellspacing=0 bgcolor=\"#E0E0E0\">\n");
8950e96539fSCharles.Forsyth		g.print("<TR>");
8960e96539fSCharles.Forsyth		g.print(sprint("<TD align=left><FONT SIZE=-1>"));
8970e96539fSCharles.Forsyth		g.print(sprint("%s(%s)", g.thisone.page, g.thisone.mtype));
8980e96539fSCharles.Forsyth		g.print("</FONT></TD>\n");
8990e96539fSCharles.Forsyth		g.print(sprint("<TD align=right><FONT SIZE=-1><I>Rev:&nbsp;&nbsp;%s</I></FONT></TD></TR></TABLE>\n",
9000e96539fSCharles.Forsyth			dt->text(dt->gmt(g.mtime))));
9010e96539fSCharles.Forsyth	}
9020e96539fSCharles.Forsyth}
9030e96539fSCharles.Forsyth
9040e96539fSCharles.Forsyth#
9050e96539fSCharles.Forsyth# Some font alternation macros are references to other man pages;
9060e96539fSCharles.Forsyth# detect them (second arg contains balanced parens) and make them into hot links.
9070e96539fSCharles.Forsyth#
9080e96539fSCharles.Forsythanchor(g: ref Global, f1, f2: string, argl: list of string)
9090e96539fSCharles.Forsyth{
9100e96539fSCharles.Forsyth	final := "";
9110e96539fSCharles.Forsyth	link := false;
9120e96539fSCharles.Forsyth	if (len argl == 2) {
9130e96539fSCharles.Forsyth		(s, e) := str->splitl(hd tl argl, ")");
9140e96539fSCharles.Forsyth		if (str->prefix("(", s) && e != nil) {
9150e96539fSCharles.Forsyth			# emit href containing search for target first
9160e96539fSCharles.Forsyth			# if numeric, do old style
9170e96539fSCharles.Forsyth			link = true;
9180e96539fSCharles.Forsyth			file := hd argl;
9190e96539fSCharles.Forsyth			(chap, man) := split(httpunesc(file), '/');
9200e96539fSCharles.Forsyth			if (man == nil) {
9210e96539fSCharles.Forsyth				# given no explicit chapter prefix, use current chapter
9220e96539fSCharles.Forsyth				man = chap;
9230e96539fSCharles.Forsyth				chap = g.thisone.chap;
9240e96539fSCharles.Forsyth			}
9250e96539fSCharles.Forsyth			mtype := s[1:];
9260e96539fSCharles.Forsyth			if (mtype == nil)
9270e96539fSCharles.Forsyth				mtype = "-";
9280e96539fSCharles.Forsyth			(n, toks) := sys->tokenize(mtype, ".");	# Fix section 10
9290e96539fSCharles.Forsyth			if (n > 1) mtype = hd toks;
9300e96539fSCharles.Forsyth			g.print(sprint("<A href=\"../%s/%s.html\">", mtype, fixlink(man)));
9310e96539fSCharles.Forsyth
9320e96539fSCharles.Forsyth			#
9330e96539fSCharles.Forsyth			# now generate the name the user sees, with terminal punctuation
9340e96539fSCharles.Forsyth			# moved after the closing </A>.
9350e96539fSCharles.Forsyth			#
9360e96539fSCharles.Forsyth			if (len e > 1)
9370e96539fSCharles.Forsyth				final = e[1:];
9380e96539fSCharles.Forsyth			argl = hd argl :: s + ")" :: nil;
9390e96539fSCharles.Forsyth		}
9400e96539fSCharles.Forsyth	}
9410e96539fSCharles.Forsyth	altfont(g, f1, f2, argl, false);
9420e96539fSCharles.Forsyth	if (link) {
9430e96539fSCharles.Forsyth		g.print("</A>");
9440e96539fSCharles.Forsyth		font(g, f2, final :: nil);
9450e96539fSCharles.Forsyth	} else
9460e96539fSCharles.Forsyth		g.print("\n");
9470e96539fSCharles.Forsyth}
9480e96539fSCharles.Forsyth
9490e96539fSCharles.Forsyth
9500e96539fSCharles.Forsyth#
9510e96539fSCharles.Forsyth# Fix up a link
9520e96539fSCharles.Forsyth#
9530e96539fSCharles.Forsyth
9540e96539fSCharles.Forsythfixlink(l: string): string
9550e96539fSCharles.Forsyth{
9560e96539fSCharles.Forsyth	ll := str->tolower(l);
9570e96539fSCharles.Forsyth	if (ll == "copyright") ll = "1" + ll;
9580e96539fSCharles.Forsyth	(a, b) := str->splitstrl(ll, "intro");
9590e96539fSCharles.Forsyth	if (len b == 5) ll = a + "0" + b;
9600e96539fSCharles.Forsyth	return ll;
9610e96539fSCharles.Forsyth}
9620e96539fSCharles.Forsyth
9630e96539fSCharles.Forsyth
9640e96539fSCharles.Forsyth#
9650e96539fSCharles.Forsyth# output argl in font f
9660e96539fSCharles.Forsyth#
9670e96539fSCharles.Forsythfont(g: ref Global, f: string, argl: list of string)
9680e96539fSCharles.Forsyth{
9690e96539fSCharles.Forsyth	if (argl == nil) {
9700e96539fSCharles.Forsyth		g.def_goobie = f;
9710e96539fSCharles.Forsyth		return;
9720e96539fSCharles.Forsyth	}
9730e96539fSCharles.Forsyth	case f {
9740e96539fSCharles.Forsyth	"L" => 	f = "TT";
9750e96539fSCharles.Forsyth	"R" =>	f = nil;
9760e96539fSCharles.Forsyth	}
9770e96539fSCharles.Forsyth	if (f != nil) 			# nil == default (typically Roman)
9780e96539fSCharles.Forsyth		g.print(sprint("<%s>", f));
9790e96539fSCharles.Forsyth	printargs(g, argl);
9800e96539fSCharles.Forsyth	if (f != nil)
9810e96539fSCharles.Forsyth		g.print(sprint("</%s>", f));
9820e96539fSCharles.Forsyth	g.print("\n");
9830e96539fSCharles.Forsyth	g.prevfont = f;
9840e96539fSCharles.Forsyth}
9850e96539fSCharles.Forsyth
9860e96539fSCharles.Forsyth#
9870e96539fSCharles.Forsyth# output concatenated elements of argl, alternating between fonts f1 and f2
9880e96539fSCharles.Forsyth#
9890e96539fSCharles.Forsythaltfont(g: ref Global, f1, f2: string, argl: list of string, newline: int)
9900e96539fSCharles.Forsyth{
9910e96539fSCharles.Forsyth	reset_font(g);
9920e96539fSCharles.Forsyth	if (argl == nil) {
9930e96539fSCharles.Forsyth		g.def_goobie = f1;
9940e96539fSCharles.Forsyth		return;
9950e96539fSCharles.Forsyth	}
9960e96539fSCharles.Forsyth	case f1 {
9970e96539fSCharles.Forsyth	"L" =>	f1 = "TT";
9980e96539fSCharles.Forsyth	"R" =>	f1 = nil;
9990e96539fSCharles.Forsyth	}
10000e96539fSCharles.Forsyth	case f2 {
10010e96539fSCharles.Forsyth	"L" =>	f2 = "TT";
10020e96539fSCharles.Forsyth	"R" =>	f2 = nil;
10030e96539fSCharles.Forsyth	}
10040e96539fSCharles.Forsyth	f := f1;
10050e96539fSCharles.Forsyth	for (; argl != nil; argl = tl argl) {
10060e96539fSCharles.Forsyth		if (f != nil)
10070e96539fSCharles.Forsyth			g.print(sprint("<%s>%s</%s>", f, hd argl, f));
10080e96539fSCharles.Forsyth		else
10090e96539fSCharles.Forsyth			g.print(hd argl);
10100e96539fSCharles.Forsyth		if (f == f1)
10110e96539fSCharles.Forsyth			f = f2;
10120e96539fSCharles.Forsyth		else
10130e96539fSCharles.Forsyth			f = f1;
10140e96539fSCharles.Forsyth	}
10150e96539fSCharles.Forsyth	if (newline)
10160e96539fSCharles.Forsyth		g.print("\n");
10170e96539fSCharles.Forsyth	g.prevfont = f;
10180e96539fSCharles.Forsyth}
10190e96539fSCharles.Forsyth
10200e96539fSCharles.Forsyth# not yet implemented
10210e96539fSCharles.Forsythmap_font(nil: ref Global, nil: string)
10220e96539fSCharles.Forsyth{
10230e96539fSCharles.Forsyth}
10240e96539fSCharles.Forsyth
10250e96539fSCharles.Forsythreset_font(g: ref Global)
10260e96539fSCharles.Forsyth{
10270e96539fSCharles.Forsyth	if (g.curfont != nil) {
10280e96539fSCharles.Forsyth		g.print(sprint("</%s>", g.curfont));
10290e96539fSCharles.Forsyth		g.prevfont = g.curfont;
10300e96539fSCharles.Forsyth		g.curfont = nil;
10310e96539fSCharles.Forsyth	}
10320e96539fSCharles.Forsyth}
10330e96539fSCharles.Forsyth
10340e96539fSCharles.Forsythprintargs(g: ref Global, argl: list of string)
10350e96539fSCharles.Forsyth{
10360e96539fSCharles.Forsyth	for (; argl != nil; argl = tl argl)
10370e96539fSCharles.Forsyth		if (tl argl != nil)
10380e96539fSCharles.Forsyth			g.print(hd argl + " ");
10390e96539fSCharles.Forsyth		else
10400e96539fSCharles.Forsyth			g.print(hd argl);
10410e96539fSCharles.Forsyth}
10420e96539fSCharles.Forsyth
10430e96539fSCharles.Forsyth# any parameter can be nil
10440e96539fSCharles.Forsythaddhit(g: ref Global, chap, mtype, page: string)
10450e96539fSCharles.Forsyth{
10460e96539fSCharles.Forsyth	# g.print(sprint("Adding %s / %s (%s) . . .", chap, page, mtype));		# debug
10470e96539fSCharles.Forsyth	# always keep a spare slot at the end
10480e96539fSCharles.Forsyth	if (g.nhits >= len g.hits - 1)
10490e96539fSCharles.Forsyth		g.hits = (array[len g.hits + 32] of Hit)[0:] = g.hits;
10500e96539fSCharles.Forsyth	g.hits[g.nhits].glob = chap + " " + mtype + " " + page;
10510e96539fSCharles.Forsyth	g.hits[g.nhits].chap = chap;
10520e96539fSCharles.Forsyth	g.hits[g.nhits].mtype = mtype;
10530e96539fSCharles.Forsyth	g.hits[g.nhits++].page = page;
10540e96539fSCharles.Forsyth}
10550e96539fSCharles.Forsyth
10560e96539fSCharles.ForsythGlobal.dobreak(g: self ref Global)
10570e96539fSCharles.Forsyth{
10580e96539fSCharles.Forsyth	if (! g.broken) {
10590e96539fSCharles.Forsyth		g.broken = true;
10600e96539fSCharles.Forsyth		g.print("<BR>\n");
10610e96539fSCharles.Forsyth	}
10620e96539fSCharles.Forsyth}
10630e96539fSCharles.Forsyth
10640e96539fSCharles.ForsythGlobal.print(g: self ref Global, s: string)
10650e96539fSCharles.Forsyth{
10660e96539fSCharles.Forsyth	g.bufio->g.bout.puts(s);
10670e96539fSCharles.Forsyth	if (g.sop || g.broken) {
10680e96539fSCharles.Forsyth		# first non-white space, non-HTML we print takes us past the start of the paragraph & line
10690e96539fSCharles.Forsyth		# (or even white space, if we're in no-fill mode)
10700e96539fSCharles.Forsyth		for (i := 0; i < len s; i++) {
10710e96539fSCharles.Forsyth			case s[i] {
10720e96539fSCharles.Forsyth			'<' =>
10730e96539fSCharles.Forsyth				while (++i < len s && s[i] != '>')
10740e96539fSCharles.Forsyth					;
10750e96539fSCharles.Forsyth				continue;
10760e96539fSCharles.Forsyth			' ' or '\t' or '\n' =>
10770e96539fSCharles.Forsyth				if (g.fill)
10780e96539fSCharles.Forsyth					continue;
10790e96539fSCharles.Forsyth			}
10800e96539fSCharles.Forsyth			g.sop = false;
10810e96539fSCharles.Forsyth			g.broken = false;
10820e96539fSCharles.Forsyth			break;
10830e96539fSCharles.Forsyth		}
10840e96539fSCharles.Forsyth	}
10850e96539fSCharles.Forsyth}
10860e96539fSCharles.Forsyth
10870e96539fSCharles.ForsythGlobal.softbr(g: self ref Global): string
10880e96539fSCharles.Forsyth{
10890e96539fSCharles.Forsyth	if (g.broken)
10900e96539fSCharles.Forsyth		return nil;
10910e96539fSCharles.Forsyth	g.broken = true;
10920e96539fSCharles.Forsyth	return "<BR>";
10930e96539fSCharles.Forsyth}
10940e96539fSCharles.Forsyth
10950e96539fSCharles.Forsyth# provide a paragraph marker, unless we're already at the start of a section
10960e96539fSCharles.ForsythGlobal.softp(g: self ref Global): string
10970e96539fSCharles.Forsyth{
10980e96539fSCharles.Forsyth	if (g.sop)
10990e96539fSCharles.Forsyth		return nil;
11000e96539fSCharles.Forsyth	else if (! g.ipd)
11010e96539fSCharles.Forsyth		return "<BR>";
11020e96539fSCharles.Forsyth	if (g.fill)
11030e96539fSCharles.Forsyth		return "<P>";
11040e96539fSCharles.Forsyth	else
11050e96539fSCharles.Forsyth		return "<P style=\"white-space: pre\">";
11060e96539fSCharles.Forsyth}
11070e96539fSCharles.Forsyth
11080e96539fSCharles.Forsyth#
110979aa5773SCharles.Forsyth# get (remainder of) a line
111079aa5773SCharles.Forsyth#
111179aa5773SCharles.Forsythgetline(g: ref Global): string
111279aa5773SCharles.Forsyth{
111379aa5773SCharles.Forsyth	line := "";
111479aa5773SCharles.Forsyth	while ((token := getnext(g)) != "\n") {
111579aa5773SCharles.Forsyth		if (token == nil)
111679aa5773SCharles.Forsyth			return line;
111779aa5773SCharles.Forsyth		line += token;
111879aa5773SCharles.Forsyth	}
111979aa5773SCharles.Forsyth	return line+"\n";
112079aa5773SCharles.Forsyth}
112179aa5773SCharles.Forsyth
112279aa5773SCharles.Forsyth#
11230e96539fSCharles.Forsyth# Get next logical character.  Expand it with escapes.
11240e96539fSCharles.Forsyth#
11250e96539fSCharles.Forsythgetnext(g: ref Global): string
11260e96539fSCharles.Forsyth{
11270e96539fSCharles.Forsyth	iob := g.bufio;
11280e96539fSCharles.Forsyth	Iobuf: import iob;
11290e96539fSCharles.Forsyth
11300e96539fSCharles.Forsyth	font: string;
11310e96539fSCharles.Forsyth	token: string;
11320e96539fSCharles.Forsyth	bin := g.bin;
11330e96539fSCharles.Forsyth
11340e96539fSCharles.Forsyth	g.sol = (g.lastc == '\n');
11350e96539fSCharles.Forsyth
11360e96539fSCharles.Forsyth	c := bin.getc();
11370e96539fSCharles.Forsyth	if (c < 0)
11380e96539fSCharles.Forsyth		return nil;
11390e96539fSCharles.Forsyth	g.lastc = c;
11400e96539fSCharles.Forsyth	if (c >= Runeself) {
11410e96539fSCharles.Forsyth		for (i := 0;  i < len Entities; i++)
11420e96539fSCharles.Forsyth			if (Entities[i].value == c)
11430e96539fSCharles.Forsyth				return Entities[i].name;
11440e96539fSCharles.Forsyth		return sprint("&#%d;", c);
11450e96539fSCharles.Forsyth	}
11460e96539fSCharles.Forsyth	case c {
11470e96539fSCharles.Forsyth	'<' =>
11480e96539fSCharles.Forsyth		return "&lt;";
11490e96539fSCharles.Forsyth	'>' =>
11500e96539fSCharles.Forsyth		return "&gt;";
11510e96539fSCharles.Forsyth	'\\' =>
11520e96539fSCharles.Forsyth		c = bin.getc();
11530e96539fSCharles.Forsyth		if (c < 0)
11540e96539fSCharles.Forsyth			return nil;
11550e96539fSCharles.Forsyth		g.lastc = c;
11560e96539fSCharles.Forsyth		case c {
11570e96539fSCharles.Forsyth
115867caa6f2SCharles.Forsyth		' ' =>
115967caa6f2SCharles.Forsyth			return "&nbsp;";
116067caa6f2SCharles.Forsyth
11610e96539fSCharles.Forsyth		# chars to ignore
11620e96539fSCharles.Forsyth		'|' or '&' or '^' =>
11630e96539fSCharles.Forsyth			return getnext(g);
11640e96539fSCharles.Forsyth
11650e96539fSCharles.Forsyth		# ignore arg
11660e96539fSCharles.Forsyth		'k' =>
11670e96539fSCharles.Forsyth			nil = bin.getc();
11680e96539fSCharles.Forsyth			return getnext(g);
11690e96539fSCharles.Forsyth
11700e96539fSCharles.Forsyth		# defined strings
11710e96539fSCharles.Forsyth		'*' =>
11720e96539fSCharles.Forsyth			case bin.getc() {
11730e96539fSCharles.Forsyth			'R' =>
11740e96539fSCharles.Forsyth				return "&#174;";
11750e96539fSCharles.Forsyth			}
11760e96539fSCharles.Forsyth			return getnext(g);
11770e96539fSCharles.Forsyth
11780e96539fSCharles.Forsyth		# special chars
11790e96539fSCharles.Forsyth		'(' =>
11800e96539fSCharles.Forsyth			token[0] = bin.getc();
11810e96539fSCharles.Forsyth			token[1] = bin.getc();
11820e96539fSCharles.Forsyth			for (i := 0; i < len tspec; i++)
11830e96539fSCharles.Forsyth				if (token == tspec[i].name)
11840e96539fSCharles.Forsyth					return tspec[i].value;
11850e96539fSCharles.Forsyth			return "&#191;";
11860e96539fSCharles.Forsyth		'c' =>
11870e96539fSCharles.Forsyth			c = bin.getc();
11880e96539fSCharles.Forsyth			if (c < 0)
11890e96539fSCharles.Forsyth				return nil;
11900e96539fSCharles.Forsyth			else if (c == '\n') {
11910e96539fSCharles.Forsyth				g.lastc = c;
11920e96539fSCharles.Forsyth				g.sol = true;
11930e96539fSCharles.Forsyth				token[0] = bin.getc();
11940e96539fSCharles.Forsyth				return token;
11950e96539fSCharles.Forsyth			}
11960e96539fSCharles.Forsyth			# DEBUG: should there be a "return xxx" here?
11970e96539fSCharles.Forsyth		'e' =>
11980e96539fSCharles.Forsyth			return "\\";
11990e96539fSCharles.Forsyth		'f' =>
12000e96539fSCharles.Forsyth			g.lastc = c = bin.getc();
12010e96539fSCharles.Forsyth			if (c < 0)
12020e96539fSCharles.Forsyth				return nil;
12030e96539fSCharles.Forsyth			case c {
12040e96539fSCharles.Forsyth			'2' or 	'I' =>
12050e96539fSCharles.Forsyth				font = "I";
12060e96539fSCharles.Forsyth			'3' or 	'B' =>
12070e96539fSCharles.Forsyth				font = "B";
12080e96539fSCharles.Forsyth			'5' or 	'L' =>
12090e96539fSCharles.Forsyth				font = "TT";
12100e96539fSCharles.Forsyth			'P' =>
12110e96539fSCharles.Forsyth				font = g.prevfont;
12120e96539fSCharles.Forsyth			* =>					# includes '1' and 'R'
12130e96539fSCharles.Forsyth				font = nil;
12140e96539fSCharles.Forsyth			}
12150e96539fSCharles.Forsyth# There are serious problems with this. We don't know the fonts properly at this stage.
12160e96539fSCharles.Forsyth#			g.prevfont = g.curfont;
12170e96539fSCharles.Forsyth#			g.curfont = font;
12180e96539fSCharles.Forsyth#			if (g.prevfont != nil)
12190e96539fSCharles.Forsyth#				token = sprint("</%s>", g.prevfont);
12200e96539fSCharles.Forsyth#			if (g.curfont != nil)
12210e96539fSCharles.Forsyth#				token += sprint("<%s>", g.curfont);
12220e96539fSCharles.Forsyth			if (token == nil)
122379aa5773SCharles.Forsyth				return "<i></i>";	# looks odd but it avoids inserting a space in <pre> text
12240e96539fSCharles.Forsyth			return token;
12250e96539fSCharles.Forsyth		's' =>
12260e96539fSCharles.Forsyth			sign := '+';
12270e96539fSCharles.Forsyth			size := 0;
12280e96539fSCharles.Forsyth			relative := false;
12290e96539fSCharles.Forsyth		getsize:
12300e96539fSCharles.Forsyth			for (;;) {
12310e96539fSCharles.Forsyth				c = bin.getc();
12320e96539fSCharles.Forsyth				if (c < 0)
12330e96539fSCharles.Forsyth					return nil;
12340e96539fSCharles.Forsyth				case c {
12350e96539fSCharles.Forsyth				'+' =>
12360e96539fSCharles.Forsyth					relative = true;
12370e96539fSCharles.Forsyth				'-' =>
12380e96539fSCharles.Forsyth					sign = '-';
12390e96539fSCharles.Forsyth					relative = true;
12400e96539fSCharles.Forsyth				'0' to '9' =>
12410e96539fSCharles.Forsyth					size = size * 10 + (c - '0');
12420e96539fSCharles.Forsyth				* =>
12430e96539fSCharles.Forsyth					bin.ungetc();
12440e96539fSCharles.Forsyth					break getsize;
12450e96539fSCharles.Forsyth				}
12460e96539fSCharles.Forsyth				g.lastc = c;
12470e96539fSCharles.Forsyth			}
12480e96539fSCharles.Forsyth			if (size == 0)
12490e96539fSCharles.Forsyth				token = "</FONT>";
12500e96539fSCharles.Forsyth			else if (relative)
12510e96539fSCharles.Forsyth				token = sprint("<FONT SIZE=%c%d>", sign, size);
12520e96539fSCharles.Forsyth			else
12530e96539fSCharles.Forsyth				token = sprint("<FONT SIZE=%d>", size);
12540e96539fSCharles.Forsyth			return token;
12550e96539fSCharles.Forsyth		}
12560e96539fSCharles.Forsyth	}
12570e96539fSCharles.Forsyth	token[0] = c;
12580e96539fSCharles.Forsyth	return token;
12590e96539fSCharles.Forsyth}
12600e96539fSCharles.Forsyth
12610e96539fSCharles.Forsyth#
12620e96539fSCharles.Forsyth# Return strings before and after the left-most instance of separator;
12630e96539fSCharles.Forsyth# (s, nil) if no match or separator is last char in s.
12640e96539fSCharles.Forsyth#
12650e96539fSCharles.Forsythsplit(s: string, sep: int): (string, string)
12660e96539fSCharles.Forsyth{
12670e96539fSCharles.Forsyth	for (i := 0; i < len s; i++)
12680e96539fSCharles.Forsyth		if (s[i] == sep)
12690e96539fSCharles.Forsyth			return (s[:i], s[i+1:]);	# s[len s:] is a valid slice, with value == nil
12700e96539fSCharles.Forsyth 	return (s, nil);
12710e96539fSCharles.Forsyth}
12720e96539fSCharles.Forsyth
12730e96539fSCharles.ForsythGlobal_init(): ref Global
12740e96539fSCharles.Forsyth{
12750e96539fSCharles.Forsyth	g := ref Global;
12760e96539fSCharles.Forsyth	g.bufio = load Bufio Bufio->PATH;
12770e96539fSCharles.Forsyth	g.chaps = array[20] of Chaps;
12780e96539fSCharles.Forsyth	g.types = array[20] of Types;
12790e96539fSCharles.Forsyth	g.mantitle = "";
12800e96539fSCharles.Forsyth	g.href.title = g.mantitle;		# ??
12810e96539fSCharles.Forsyth	g.mtime = 0;
12820e96539fSCharles.Forsyth	g.nhits = 0;
12830e96539fSCharles.Forsyth	g.oldstyle.names = false;
12840e96539fSCharles.Forsyth	g.oldstyle.fmt = false;
12850e96539fSCharles.Forsyth	g.topname = "System";
12860e96539fSCharles.Forsyth	g.list_type = Lnone;
12870e96539fSCharles.Forsyth	g.def_sm = 0;
12880e96539fSCharles.Forsyth	g.hangingdt = 0;
12890e96539fSCharles.Forsyth	g.indents = 0;
12900e96539fSCharles.Forsyth	g.sop = true;
12910e96539fSCharles.Forsyth	g.broken = true;
12920e96539fSCharles.Forsyth	g.ipd = true;
12930e96539fSCharles.Forsyth	g.fill = true;
12940e96539fSCharles.Forsyth	g.example = false;
12950e96539fSCharles.Forsyth	g.pre = false;
12960e96539fSCharles.Forsyth	g.lastc = '\n';
12970e96539fSCharles.Forsyth	return g;
12980e96539fSCharles.Forsyth}
12990e96539fSCharles.Forsyth
13000e96539fSCharles.ForsythGlobal.mk_href_chap(g: self ref Global, chap: string)
13010e96539fSCharles.Forsyth{
13020e96539fSCharles.Forsyth	if (chap != nil)
13030e96539fSCharles.Forsyth		g.href.chap = sprint("<A href=\"%s/%s?man=*\"><B>%s</B></A>", g.mandir, chap, chap);
13040e96539fSCharles.Forsyth}
13050e96539fSCharles.Forsyth
13060e96539fSCharles.ForsythGlobal.mk_href_man(g: self ref Global, man: string, oldstyle: int)
13070e96539fSCharles.Forsyth{
13080e96539fSCharles.Forsyth	rman := man;
13090e96539fSCharles.Forsyth	if (oldstyle)
13100e96539fSCharles.Forsyth		rman = str->tolower(man);	# compensate for tradition of putting titles in all CAPS
13110e96539fSCharles.Forsyth	g.href.man = sprint("<A href=\"%s?man=%s\"><B>%s</B></A>", g.mandir, rman, man);
13120e96539fSCharles.Forsyth}
13130e96539fSCharles.Forsyth
13140e96539fSCharles.ForsythGlobal.mk_href_mtype(g: self ref Global, chap, mtype: string)
13150e96539fSCharles.Forsyth{
13160e96539fSCharles.Forsyth	g.href.mtype = sprint("<A href=\"%s/%s/%s\"><B>%s</B></A>", g.mandir, chap, mtype, mtype);
13170e96539fSCharles.Forsyth}
13180e96539fSCharles.Forsyth
13190e96539fSCharles.Forsyth# We assume that anything >= Runeself is already in UTF.
13200e96539fSCharles.Forsyth#
13210e96539fSCharles.Forsythhttpunesc(s: string): string
13220e96539fSCharles.Forsyth{
13230e96539fSCharles.Forsyth	t := "";
13240e96539fSCharles.Forsyth	for (i := 0; i < len s; i++) {
13250e96539fSCharles.Forsyth		c := s[i];
13260e96539fSCharles.Forsyth		if (c == '&' && i + 1 < len s) {
13270e96539fSCharles.Forsyth			(char, rem) := str->splitl(s[i+1:], ";");
13280e96539fSCharles.Forsyth			if (rem == nil)
13290e96539fSCharles.Forsyth				break;	# require the terminating ';'
13300e96539fSCharles.Forsyth			if (char == nil)
13310e96539fSCharles.Forsyth				continue;
13320e96539fSCharles.Forsyth			if (char[0] == '#' && len char > 1) {
13330e96539fSCharles.Forsyth				c = int char[1:];
13340e96539fSCharles.Forsyth				i += len char;
13350e96539fSCharles.Forsyth				if (c < 256 && c >= 161) {
13360e96539fSCharles.Forsyth					t[len t] = Entities[c-161].value;
13370e96539fSCharles.Forsyth					continue;
13380e96539fSCharles.Forsyth				}
13390e96539fSCharles.Forsyth			} else {
13400e96539fSCharles.Forsyth				for (j := 0; j < len Entities; j++)
13410e96539fSCharles.Forsyth					if (Entities[j].name == char)
13420e96539fSCharles.Forsyth						break;
13430e96539fSCharles.Forsyth				if (j < len Entities) {
13440e96539fSCharles.Forsyth					i += len char;
13450e96539fSCharles.Forsyth					t[len t] = Entities[j].value;
13460e96539fSCharles.Forsyth					continue;
13470e96539fSCharles.Forsyth				}
13480e96539fSCharles.Forsyth			}
13490e96539fSCharles.Forsyth		}
13500e96539fSCharles.Forsyth		t[len t] = c;
13510e96539fSCharles.Forsyth	}
13520e96539fSCharles.Forsyth	return t;
13530e96539fSCharles.Forsyth}
13540e96539fSCharles.Forsyth
13550e96539fSCharles.Forsyth
13560e96539fSCharles.Forsyth
13570e96539fSCharles.Forsythtitle(g: ref Global, t: string, search: int)
13580e96539fSCharles.Forsyth{
13590e96539fSCharles.Forsyth	if(search)
13600e96539fSCharles.Forsyth		;	# not yet used
136130dcb98cSCharles.Forsyth	g.print(header+"\n");
13620e96539fSCharles.Forsyth	g.print(sprint("<TITLE>Inferno's %s</TITLE>\n", demark(t)));
13630e96539fSCharles.Forsyth	g.print("</HEAD>\n");
1364*7cdb1d14SCharles.Forsyth	g.print("<BODY>"+initial+"\n");
13650e96539fSCharles.Forsyth
13660e96539fSCharles.Forsyth}
1367