4019 lines
		
	
	
	
		
			81 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			4019 lines
		
	
	
	
		
			81 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * This program was written by Richard Verhoeven (NL:5482ZX35) | ||
|  |  * at the Eindhoven University of Technology. Email: rcb5@win.tue.nl | ||
|  |  * | ||
|  |  * Permission is granted to distribute, modify and use this program as long | ||
|  |  * as this comment is not removed or changed. | ||
|  |  * | ||
|  |  * THIS IS A MODIFIED VERSION.  IT WAS MODIFIED BY chet@po.cwru.edu FOR | ||
|  |  * USE BY BASH. | ||
|  |  */ | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * man2html will add links to the converted manpages. The function add_links | ||
|  |  * is used for that. At the moment it will add links as follows, where | ||
|  |  *     indicates what should match to start with: | ||
|  |  * ^^^ | ||
|  |  * Recognition           Item            Link | ||
|  |  * ---------------------------------------------------------- | ||
|  |  * name(*)               Manpage         ../man?/name.* | ||
|  |  *     ^ | ||
|  |  * name@hostname         Email address   mailto:name@hostname | ||
|  |  *     ^ | ||
|  |  * method://string       URL             method://string
 | ||
|  |  *       ^^^ | ||
|  |  * www.host.name         WWW server      http://www.host.name
 | ||
|  |  * ^^^^ | ||
|  |  * ftp.host.name         FTP server      ftp://ftp.host.name
 | ||
|  |  * ^^^^ | ||
|  |  * <file.h>              Include file    file:/usr/include/file.h | ||
|  |  *      ^^^ | ||
|  |  * | ||
|  |  * Since man2html does not check if manpages, hosts or email addresses exist, | ||
|  |  * some links might not work. For manpages, some extra checks are performed | ||
|  |  * to make sure not every () pair creates a link. Also out of date pages | ||
|  |  * might point to incorrect places. | ||
|  |  * | ||
|  |  * The program will not allow users to get system specific files, such as | ||
|  |  * /etc/passwd. It will check that "man" is part of the specified file and | ||
|  |  * that  "/../" isn't. Even if someone manages to get such file, man2html will | ||
|  |  * handle it like a manpage and will usually not produce any output (or crash). | ||
|  |  * | ||
|  |  * If you find any bugs when normal manpages are converted, please report | ||
|  |  * them to me (rcb5@win.tue.nl) after you have checked that man(1) can handle | ||
|  |  * the manpage correct. | ||
|  |  * | ||
|  |  * Known bugs and missing features: | ||
|  |  * | ||
|  |  *  * Equations are not converted at all. | ||
|  |  *  * Tables are converted but some features are not possible in html. | ||
|  |  *  * The tabbing environment is converted by counting characters and adding | ||
|  |  *    spaces. This might go wrong (outside <PRE>) | ||
|  |  *  * Some pages look beter if man2html works in troff mode, especially pages | ||
|  |  *    with tables. You can deside at compile time which made you want to use. | ||
|  |  * | ||
|  |  *    -DNROFF=0     troff mode | ||
|  |  *    -DNROFF=1     nroff mode   (default) | ||
|  |  * | ||
|  |  *    if you install both modes, you should compile with the correct CGIBASE. | ||
|  |  *  * Some manpages rely on the fact that troff/nroff is used to convert | ||
|  |  *    them and use features which are not descripted in the man manpages. | ||
|  |  *    (definitions, calculations, conditionals, requests). I can't guarantee | ||
|  |  *    that all these features work on all manpages. (I didn't have the | ||
|  |  *    time to look through all the available manpages.) | ||
|  |  */ | ||
|  | #ifdef HAVE_CONFIG_H
 | ||
|  | #include <config.h>
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #define NROFF 0
 | ||
|  | 
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <string.h>
 | ||
|  | #include <sys/stat.h>
 | ||
|  | #include <ctype.h>
 | ||
|  | #include <sys/types.h>
 | ||
|  | #include <time.h>
 | ||
|  | #include <sys/time.h>
 | ||
|  | #include <errno.h>
 | ||
|  | 
 | ||
|  | #define NULL_TERMINATED(n) ((n) + 1)
 | ||
|  | 
 | ||
|  | #define HUGE_STR_MAX  10000
 | ||
|  | #define LARGE_STR_MAX 2000
 | ||
|  | #define MED_STR_MAX   500
 | ||
|  | #define SMALL_STR_MAX 100
 | ||
|  | #define TINY_STR_MAX  10
 | ||
|  | 
 | ||
|  | #define MAX_MAN_PATHS 100	/* Max number of directories */
 | ||
|  | #define MAX_ZCATS     10	/* Max number of zcat style programs */
 | ||
|  | #define MAX_WORDLIST  100
 | ||
|  | 
 | ||
|  | #ifndef EXIT_SUCCESS
 | ||
|  | #define EXIT_SUCCESS 0
 | ||
|  | #endif
 | ||
|  | #ifndef EXIT_FAILURE
 | ||
|  | #define EXIT_FAILURE 1
 | ||
|  | #endif
 | ||
|  | #ifndef EXIT_USAGE
 | ||
|  | #define EXIT_USAGE 2
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | static char location_base[NULL_TERMINATED(MED_STR_MAX)] = ""; | ||
|  | 
 | ||
|  | char   *signature = "<HR>\n" | ||
|  | "This document was created by man2html\n" | ||
|  | "using the manual pages.<BR>\n" | ||
|  | "Time: %s\n"; | ||
|  | 
 | ||
|  | /* timeformat for signature */ | ||
|  | #define TIMEFORMAT "%T GMT, %B %d, %Y"
 | ||
|  | 
 | ||
|  | /* BSD mandoc Bl/El lists to HTML list types */ | ||
|  | #define BL_DESC_LIST   1
 | ||
|  | #define BL_BULLET_LIST 2
 | ||
|  | #define BL_ENUM_LIST   4
 | ||
|  | 
 | ||
|  | /* BSD mandoc Bd/Ed example(?) blocks */ | ||
|  | #define BD_LITERAL  1
 | ||
|  | #define BD_INDENT   2
 | ||
|  | 
 | ||
|  | #ifndef HAVE_STRERROR
 | ||
|  | static char * | ||
|  | strerror(int e) | ||
|  | { | ||
|  | 	static char emsg[40]; | ||
|  | 
 | ||
|  | #if defined (HAVE_SYS_ERRLIST)
 | ||
|  | 	extern int sys_nerr; | ||
|  | 	extern char *sys_errlist[]; | ||
|  | 
 | ||
|  | 	if (e > 0 && e < sys_nerr) | ||
|  | 		return (sys_errlist[e]); | ||
|  | 	else | ||
|  | #endif				/* HAVE_SYS_ERRLIST */
 | ||
|  | 	{ | ||
|  | 		sprintf(emsg, "Unknown system error %d", e); | ||
|  | 		return (&emsg[0]); | ||
|  | 	} | ||
|  | } | ||
|  | #endif				/* !HAVE_STRERROR */
 | ||
|  | 
 | ||
|  | static char * | ||
|  | strgrow(char *old, int len) | ||
|  | { | ||
|  | 	char   *new = realloc(old, (strlen(old) + len + 1) * sizeof(char)); | ||
|  | 
 | ||
|  | 	if (!new) { | ||
|  | 		fprintf(stderr, "man2html: out of memory"); | ||
|  | 		exit(EXIT_FAILURE); | ||
|  | 	} | ||
|  | 	return new; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | stralloc(int len) | ||
|  | { | ||
|  | 	/* allocate enough for len + NULL */ | ||
|  | 	char   *new = malloc((len + 1) * sizeof(char)); | ||
|  | 
 | ||
|  | 	if (!new) { | ||
|  | 		fprintf(stderr, "man2html: out of memory"); | ||
|  | 		exit(EXIT_FAILURE); | ||
|  | 	} | ||
|  | 	return new; | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Some systems don't have strdup so lets use our own - which can also | ||
|  |  * check for out of memory. | ||
|  |  */ | ||
|  | static char * | ||
|  | strduplicate(char *from) | ||
|  | { | ||
|  | 	char   *new = stralloc(strlen(from)); | ||
|  | 
 | ||
|  | 	strcpy(new, from); | ||
|  | 	return new; | ||
|  | } | ||
|  | 
 | ||
|  | /* Assumes space for n plus a null */ | ||
|  | static char * | ||
|  | strmaxcpy(char *to, char *from, int n) | ||
|  | { | ||
|  | 	int     len = strlen(from); | ||
|  | 
 | ||
|  | 	strncpy(to, from, n); | ||
|  | 	to[(len <= n) ? len : n] = '\0'; | ||
|  | 	return to; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | strmaxcat(char *to, char *from, int n) | ||
|  | { | ||
|  | 	int     to_len = strlen(to); | ||
|  | 
 | ||
|  | 	if (to_len < n) { | ||
|  | 		int     from_len = strlen(from); | ||
|  | 		int     cp = (to_len + from_len <= n) ? from_len : n - to_len; | ||
|  | 
 | ||
|  | 		strncpy(to + to_len, from, cp); | ||
|  | 		to[to_len + cp] = '\0'; | ||
|  | 	} | ||
|  | 	return to; | ||
|  | } | ||
|  | 
 | ||
|  | /* Assumes space for limit plus a null */ | ||
|  | static char * | ||
|  | strlimitcpy(char *to, char *from, int n, int limit) | ||
|  | { | ||
|  | 	int     len = n > limit ? limit : n; | ||
|  | 
 | ||
|  | 	strmaxcpy(to, from, len); | ||
|  | 	to[len] = '\0'; | ||
|  | 	return to; | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * takes string and escapes all metacharacters.  should be used before | ||
|  |  * including string in system() or similar call. | ||
|  |  */ | ||
|  | static char * | ||
|  | escape_input(char *str) | ||
|  | { | ||
|  | 	int     i, j = 0; | ||
|  | 	static char new[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 
 | ||
|  | 	if (strlen(str) * 2 + 1 > MED_STR_MAX) { | ||
|  | 		fprintf(stderr, | ||
|  | 			"man2html: escape_input - str too long:\n%-80s...\n", | ||
|  | 			str); | ||
|  | 		exit(EXIT_FAILURE); | ||
|  | 	} | ||
|  | 	for (i = 0; i < strlen(str); i++) { | ||
|  | 		if (!(((str[i] >= 'A') && (str[i] <= 'Z')) || | ||
|  | 		      ((str[i] >= 'a') && (str[i] <= 'z')) || | ||
|  | 		      ((str[i] >= '0') && (str[i] <= '9')))) { | ||
|  | 			new[j] = '\\'; | ||
|  | 			j++; | ||
|  | 		} | ||
|  | 		new[j] = str[i]; | ||
|  | 		j++; | ||
|  | 	} | ||
|  | 	new[j] = '\0'; | ||
|  | 	return new; | ||
|  | } | ||
|  | 
 | ||
|  | static void | ||
|  | usage(void) | ||
|  | { | ||
|  | 	fprintf(stderr, "man2html: usage: man2html filename\n"); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * below this you should not change anything unless you know a lot | ||
|  |  * about this program or about troff. | ||
|  |  */ | ||
|  | 
 | ||
|  | typedef struct STRDEF STRDEF; | ||
|  | struct STRDEF { | ||
|  | 	int     nr, slen; | ||
|  | 	char   *st; | ||
|  | 	STRDEF *next; | ||
|  | }; | ||
|  | 
 | ||
|  | typedef struct INTDEF INTDEF; | ||
|  | struct INTDEF { | ||
|  | 	int     nr; | ||
|  | 	int     val; | ||
|  | 	int     incr; | ||
|  | 	INTDEF *next; | ||
|  | }; | ||
|  | 
 | ||
|  | static char NEWLINE[2] = "\n"; | ||
|  | static char idxlabel[6] = "ixAAA"; | ||
|  | 
 | ||
|  | #define INDEXFILE "/tmp/manindex.list"
 | ||
|  | 
 | ||
|  | static char *fname; | ||
|  | static FILE *idxfile; | ||
|  | 
 | ||
|  | static STRDEF *chardef, *strdef, *defdef; | ||
|  | static INTDEF *intdef; | ||
|  | 
 | ||
|  | #define V(A,B) ((A)*256+(B))
 | ||
|  | 
 | ||
|  | static INTDEF standardint[] = { | ||
|  | 	{V('n', ' '), NROFF, 0, NULL}, | ||
|  | 	{V('t', ' '), 1 - NROFF, 0, NULL}, | ||
|  | 	{V('o', ' '), 1, 0, NULL}, | ||
|  | 	{V('e', ' '), 0, 0, NULL}, | ||
|  | 	{V('.', 'l'), 70, 0, NULL}, | ||
|  | 	{V('.', '$'), 0, 0, NULL}, | ||
|  | 	{V('.', 'A'), NROFF, 0, NULL}, | ||
|  | 	{V('.', 'T'), 1 - NROFF, 0, NULL}, | ||
|  | 	{V('.', 'V'), 1, 0, NULL},	/* the me package tests for this */ | ||
|  | {0, 0, 0, NULL}}; | ||
|  | 
 | ||
|  | static STRDEF standardstring[] = { | ||
|  | 	{V('R', ' '), 1, "®", NULL}, | ||
|  | 	{V('l', 'q'), 2, "``", NULL}, | ||
|  | 	{V('r', 'q'), 2, "''", NULL}, | ||
|  | 	{0, 0, NULL, NULL} | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | static STRDEF standardchar[] = { | ||
|  | 	{V('*', '*'), 1, "*", NULL}, | ||
|  | 	{V('*', 'A'), 1, "A", NULL}, | ||
|  | 	{V('*', 'B'), 1, "B", NULL}, | ||
|  | 	{V('*', 'C'), 2, "Xi", NULL}, | ||
|  | 	{V('*', 'D'), 5, "Delta", NULL}, | ||
|  | 	{V('*', 'E'), 1, "E", NULL}, | ||
|  | 	{V('*', 'F'), 3, "Phi", NULL}, | ||
|  | 	{V('*', 'G'), 5, "Gamma", NULL}, | ||
|  | 	{V('*', 'H'), 5, "Theta", NULL}, | ||
|  | 	{V('*', 'I'), 1, "I", NULL}, | ||
|  | 	{V('*', 'K'), 1, "K", NULL}, | ||
|  | 	{V('*', 'L'), 6, "Lambda", NULL}, | ||
|  | 	{V('*', 'M'), 1, "M", NULL}, | ||
|  | 	{V('*', 'N'), 1, "N", NULL}, | ||
|  | 	{V('*', 'O'), 1, "O", NULL}, | ||
|  | 	{V('*', 'P'), 2, "Pi", NULL}, | ||
|  | 	{V('*', 'Q'), 3, "Psi", NULL}, | ||
|  | 	{V('*', 'R'), 1, "P", NULL}, | ||
|  | 	{V('*', 'S'), 5, "Sigma", NULL}, | ||
|  | 	{V('*', 'T'), 1, "T", NULL}, | ||
|  | 	{V('*', 'U'), 1, "Y", NULL}, | ||
|  | 	{V('*', 'W'), 5, "Omega", NULL}, | ||
|  | 	{V('*', 'X'), 1, "X", NULL}, | ||
|  | 	{V('*', 'Y'), 1, "H", NULL}, | ||
|  | 	{V('*', 'Z'), 1, "Z", NULL}, | ||
|  | 	{V('*', 'a'), 5, "alpha", NULL}, | ||
|  | 	{V('*', 'b'), 4, "beta", NULL}, | ||
|  | 	{V('*', 'c'), 2, "xi", NULL}, | ||
|  | 	{V('*', 'd'), 5, "delta", NULL}, | ||
|  | 	{V('*', 'e'), 7, "epsilon", NULL}, | ||
|  | 	{V('*', 'f'), 3, "phi", NULL}, | ||
|  | 	{V('*', 'g'), 5, "gamma", NULL}, | ||
|  | 	{V('*', 'h'), 5, "theta", NULL}, | ||
|  | 	{V('*', 'i'), 4, "iota", NULL}, | ||
|  | 	{V('*', 'k'), 5, "kappa", NULL}, | ||
|  | 	{V('*', 'l'), 6, "lambda", NULL}, | ||
|  | 	{V('*', 'm'), 1, "µ", NULL}, | ||
|  | 	{V('*', 'n'), 2, "nu", NULL}, | ||
|  | 	{V('*', 'o'), 1, "o", NULL}, | ||
|  | 	{V('*', 'p'), 2, "pi", NULL}, | ||
|  | 	{V('*', 'q'), 3, "psi", NULL}, | ||
|  | 	{V('*', 'r'), 3, "rho", NULL}, | ||
|  | 	{V('*', 's'), 5, "sigma", NULL}, | ||
|  | 	{V('*', 't'), 3, "tau", NULL}, | ||
|  | 	{V('*', 'u'), 7, "upsilon", NULL}, | ||
|  | 	{V('*', 'w'), 5, "omega", NULL}, | ||
|  | 	{V('*', 'x'), 3, "chi", NULL}, | ||
|  | 	{V('*', 'y'), 3, "eta", NULL}, | ||
|  | 	{V('*', 'z'), 4, "zeta", NULL}, | ||
|  | 	{V('t', 's'), 5, "sigma", NULL}, | ||
|  | 	{V('+', '-'), 1, "±", NULL}, | ||
|  | 	{V('1', '2'), 1, "½", NULL}, | ||
|  | 	{V('1', '4'), 1, "¼", NULL}, | ||
|  | 	{V('3', '4'), 1, "¾", NULL}, | ||
|  | 	{V('F', 'i'), 3, "ffi", NULL}, | ||
|  | 	{V('F', 'l'), 3, "ffl", NULL}, | ||
|  | 	{V('a', 'a'), 1, "´", NULL}, | ||
|  | 	{V('a', 'p'), 1, "~", NULL}, | ||
|  | 	{V('b', 'r'), 1, "|", NULL}, | ||
|  | 	{V('b', 'u'), 1, "*", NULL}, | ||
|  | 	{V('b', 'v'), 1, "|", NULL}, | ||
|  | 	{V('c', 'i'), 1, "o", NULL}, | ||
|  | 	{V('c', 'o'), 1, "©", NULL}, | ||
|  | 	{V('c', 't'), 1, "¢", NULL}, | ||
|  | 	{V('d', 'e'), 1, "°", NULL}, | ||
|  | 	{V('d', 'g'), 1, "+", NULL}, | ||
|  | 	{V('d', 'i'), 1, "÷", NULL}, | ||
|  | 	{V('e', 'm'), 1, "-", NULL}, | ||
|  | 	{V('e', 'm'), 3, "---", NULL}, | ||
|  | 	{V('e', 'q'), 1, "=", NULL}, | ||
|  | 	{V('e', 's'), 1, "Ø", NULL}, | ||
|  | 	{V('f', 'f'), 2, "ff", NULL}, | ||
|  | 	{V('f', 'i'), 2, "fi", NULL}, | ||
|  | 	{V('f', 'l'), 2, "fl", NULL}, | ||
|  | 	{V('f', 'm'), 1, "´", NULL}, | ||
|  | 	{V('g', 'a'), 1, "`", NULL}, | ||
|  | 	{V('h', 'y'), 1, "-", NULL}, | ||
|  | 	{V('l', 'c'), 2, "|¯", NULL}, | ||
|  | 	{V('l', 'f'), 2, "|_", NULL}, | ||
|  | 	{V('l', 'k'), 1, "<FONT SIZE=+2>{</FONT>", NULL}, | ||
|  | 	{V('m', 'i'), 1, "-", NULL}, | ||
|  | 	{V('m', 'u'), 1, "×", NULL}, | ||
|  | 	{V('n', 'o'), 1, "¬", NULL}, | ||
|  | 	{V('o', 'r'), 1, "|", NULL}, | ||
|  | 	{V('p', 'l'), 1, "+", NULL}, | ||
|  | 	{V('r', 'c'), 2, "¯|", NULL}, | ||
|  | 	{V('r', 'f'), 2, "_|", NULL}, | ||
|  | 	{V('r', 'g'), 1, "®", NULL}, | ||
|  | 	{V('r', 'k'), 1, "<FONT SIZE=+2>}</FONT>", NULL}, | ||
|  | 	{V('r', 'n'), 1, "¯", NULL}, | ||
|  | 	{V('r', 'u'), 1, "_", NULL}, | ||
|  | 	{V('s', 'c'), 1, "§", NULL}, | ||
|  | 	{V('s', 'l'), 1, "/", NULL}, | ||
|  | 	{V('s', 'q'), 2, "[]", NULL}, | ||
|  | 	{V('u', 'l'), 1, "_", NULL}, | ||
|  | 	{0, 0, NULL, NULL} | ||
|  | }; | ||
|  | 
 | ||
|  | /* default: print code */ | ||
|  | 
 | ||
|  | 
 | ||
|  | static char eqndelimopen = 0, eqndelimclose = 0; | ||
|  | static char escapesym = '\\', nobreaksym = '\'', controlsym = '.', fieldsym = 0, padsym = 0; | ||
|  | 
 | ||
|  | static char *buffer = NULL; | ||
|  | static int buffpos = 0, buffmax = 0; | ||
|  | static int scaninbuff = 0; | ||
|  | static int itemdepth = 0; | ||
|  | static int dl_set[20] = {0}; | ||
|  | static int still_dd = 0; | ||
|  | static int tabstops[20] = {8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96}; | ||
|  | static int maxtstop = 12; | ||
|  | static int curpos = 0; | ||
|  | 
 | ||
|  | static char *scan_troff(char *c, int san, char **result); | ||
|  | static char *scan_troff_mandoc(char *c, int san, char **result); | ||
|  | 
 | ||
|  | static char **argument = NULL; | ||
|  | 
 | ||
|  | static char charb[TINY_STR_MAX]; | ||
|  | 
 | ||
|  | static void | ||
|  | print_sig(void) | ||
|  | { | ||
|  | 	char    datbuf[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 	struct tm *timetm; | ||
|  | 	time_t  clock; | ||
|  | 
 | ||
|  | 	datbuf[0] = '\0'; | ||
|  | 	clock = time(NULL); | ||
|  | 	timetm = gmtime(&clock); | ||
|  | 	strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); | ||
|  | 	printf(signature, datbuf); | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | expand_char(int nr) | ||
|  | { | ||
|  | 	STRDEF *h; | ||
|  | 
 | ||
|  | 	h = chardef; | ||
|  | 	if (!nr) | ||
|  | 		return NULL; | ||
|  | 	while (h) | ||
|  | 		if (h->nr == nr) { | ||
|  | 			curpos += h->slen; | ||
|  | 			return h->st; | ||
|  | 		} else | ||
|  | 			h = h->next; | ||
|  | 	charb[0] = nr / 256; | ||
|  | 	charb[1] = nr % 256; | ||
|  | 	charb[2] = '\0'; | ||
|  | 	if (charb[0] == '<') {	/* Fix up <= */ | ||
|  | 		charb[4] = charb[1]; | ||
|  | 		strncpy(charb, "<", 4); | ||
|  | 		charb[5] = '\0'; | ||
|  | 	} | ||
|  | 	curpos += 2; | ||
|  | 	return charb; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | expand_string(int nr) | ||
|  | { | ||
|  | 	STRDEF *h = strdef; | ||
|  | 
 | ||
|  | 	if (!nr) | ||
|  | 		return NULL; | ||
|  | 	while (h) | ||
|  | 		if (h->nr == nr) { | ||
|  | 			curpos += h->slen; | ||
|  | 			return h->st; | ||
|  | 		} else | ||
|  | 			h = h->next; | ||
|  | 	return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | read_man_page(char *filename) | ||
|  | { | ||
|  | 	char   *man_buf = NULL; | ||
|  | 	int     i; | ||
|  | 	FILE   *man_stream = NULL; | ||
|  | 	struct stat stbuf; | ||
|  | 	int     buf_size; | ||
|  | 
 | ||
|  | 	if (stat(filename, &stbuf) == -1) | ||
|  | 		return NULL; | ||
|  | 
 | ||
|  | 	buf_size = stbuf.st_size; | ||
|  | 	man_buf = stralloc(buf_size + 5); | ||
|  | 	man_stream = fopen(filename, "r"); | ||
|  | 	if (man_stream) { | ||
|  | 		man_buf[0] = '\n'; | ||
|  | 		if (fread(man_buf + 1, 1, buf_size, man_stream) == buf_size) { | ||
|  | 			man_buf[buf_size] = '\n'; | ||
|  | 			man_buf[buf_size + 1] = man_buf[buf_size + 2] = '\0'; | ||
|  | 		} else { | ||
|  | 			man_buf = NULL; | ||
|  | 		} | ||
|  | 		fclose(man_stream); | ||
|  | 	} | ||
|  | 	return man_buf; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static char outbuffer[NULL_TERMINATED(HUGE_STR_MAX)]; | ||
|  | static int obp = 0; | ||
|  | static int no_newline_output = 0; | ||
|  | static int newline_for_fun = 0; | ||
|  | static int output_possible = 0; | ||
|  | static int out_length = 0; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Add the links to the output. At the moment the following are | ||
|  |  * recognized: | ||
|  |  *  | ||
|  | #if 0
 | ||
|  |  *	name(*)                 -> ../man?/name.* | ||
|  | #endif
 | ||
|  |  *	method://string         -> method://string
 | ||
|  |  *	www.host.name		-> http://www.host.name
 | ||
|  |  *	ftp.host.name           -> ftp://ftp.host.name
 | ||
|  |  *	name@host               -> mailto:name@host | ||
|  |  *	<name.h>                -> file:/usr/include/name.h   (guess) | ||
|  |  *  | ||
|  |  * Other possible links to add in the future: | ||
|  |  *  | ||
|  |  * /dir/dir/file  -> file:/dir/dir/file | ||
|  |  */ | ||
|  | static void | ||
|  | add_links(char *c) | ||
|  | { | ||
|  | 	int     i, j, nr; | ||
|  | 	char   *f, *g, *h; | ||
|  | 	char   *idtest[6];	/* url, mailto, www, ftp, manpage */ | ||
|  | 
 | ||
|  | 	out_length += strlen(c); | ||
|  | 	/* search for (section) */ | ||
|  | 	nr = 0; | ||
|  | 	idtest[0] = strstr(c + 1, "://"); | ||
|  | 	idtest[1] = strchr(c + 1, '@'); | ||
|  | 	idtest[2] = strstr(c, "www."); | ||
|  | 	idtest[3] = strstr(c, "ftp."); | ||
|  | #if 0
 | ||
|  | 	idtest[4] = strchr(c + 1, '('); | ||
|  | #else
 | ||
|  | 	idtest[4] = 0; | ||
|  | #endif
 | ||
|  | 	idtest[5] = strstr(c + 1, ".h>"); | ||
|  | 	for (i = 0; i < 6; i++) | ||
|  | 		nr += (idtest[i] != NULL); | ||
|  | 	while (nr) { | ||
|  | 		j = -1; | ||
|  | 		for (i = 0; i < 6; i++) | ||
|  | 			if (idtest[i] && (j < 0 || idtest[i] < idtest[j])) | ||
|  | 				j = i; | ||
|  | 		switch (j) { | ||
|  | 		case 5:	/* <name.h> */ | ||
|  | 			f = idtest[5]; | ||
|  | 			h = f + 2; | ||
|  | 			g = f; | ||
|  | 			while (g > c && g[-1] != ';') | ||
|  | 				g--; | ||
|  | 			if (g != c) { | ||
|  | 				char    t; | ||
|  | 
 | ||
|  | 				t = *g; | ||
|  | 				*g = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				*g = t; | ||
|  | 				*h = '\0'; | ||
|  | 				printf("<A HREF=\"file:/usr/include/%s\">%s</A>>", g, g); | ||
|  | 				c = f + 6; | ||
|  | 			} else { | ||
|  | 				f[5] = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				f[5] = ';'; | ||
|  | 				c = f + 5; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case 4:	/* manpage */ | ||
|  | #if 0
 | ||
|  | 			f = idtest[j]; | ||
|  | 			/* check section */ | ||
|  | 			g = strchr(f, ')'); | ||
|  | 			if (g && f - g < 6 && (isalnum(f[-1]) || f[-1] == '>') && | ||
|  | 			    ((isdigit(f[1]) && f[1] != '0' && | ||
|  | 			      (f[2] == ')' || (isalpha(f[2]) && f[3] == ')') || f[2] == 'X')) || | ||
|  | 			   (f[2] == ')' && (f[1] == 'n' || f[1] == 'l')))) { | ||
|  | 				/* this might be a link */ | ||
|  | 				h = f - 1; | ||
|  | 				/* skip html makeup */ | ||
|  | 				while (h > c && *h == '>') { | ||
|  | 					while (h != c && *h != '<') | ||
|  | 						h--; | ||
|  | 					if (h != c) | ||
|  | 						h--; | ||
|  | 				} | ||
|  | 				if (isalnum(*h)) { | ||
|  | 					char    t, sec, subsec, *e; | ||
|  | 
 | ||
|  | 					e = h + 1; | ||
|  | 					sec = f[1]; | ||
|  | 					subsec = f[2]; | ||
|  | 					if ((subsec == 'X' && f[3] != ')') || subsec == ')') | ||
|  | 						subsec = '\0'; | ||
|  | 					while (h > c && (isalnum(h[-1]) || h[-1] == '_' || | ||
|  | 					      h[-1] == '-' || h[-1] == '.')) | ||
|  | 						h--; | ||
|  | 					t = *h; | ||
|  | 					*h = '\0'; | ||
|  | 					fputs(c, stdout); | ||
|  | 					*h = t; | ||
|  | 					t = *e; | ||
|  | 					*e = '\0'; | ||
|  | 					if (subsec) | ||
|  | 						printf("<A HREF=\"" | ||
|  | 						       CGIBASE | ||
|  | 						  "?man%c/%s.%c%c\">%s</A>", | ||
|  | 						       sec, h, sec, tolower(subsec), h); | ||
|  | 					else | ||
|  | 						printf("<A HREF=\"" | ||
|  | 						       CGIBASE | ||
|  | 						    "?man%c/%s.%c\">%s</A>", | ||
|  | 						       sec, h, sec, h); | ||
|  | 					*e = t; | ||
|  | 					c = e; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			*f = '\0'; | ||
|  | 			fputs(c, stdout); | ||
|  | 			*f = '('; | ||
|  | 			idtest[4] = f - 1; | ||
|  | 			c = f; | ||
|  | #endif
 | ||
|  | 			break;	/* manpage */ | ||
|  | 		case 3:	/* ftp */ | ||
|  | 		case 2:	/* www */ | ||
|  | 			g = f = idtest[j]; | ||
|  | 			while (*g && (isalnum(*g) || *g == '_' || *g == '-' || *g == '+' || | ||
|  | 				      *g == '.')) | ||
|  | 				g++; | ||
|  | 			if (g[-1] == '.') | ||
|  | 				g--; | ||
|  | 			if (g - f > 4) { | ||
|  | 				char    t; | ||
|  | 
 | ||
|  | 				t = *f; | ||
|  | 				*f = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				*f = t; | ||
|  | 				t = *g; | ||
|  | 				*g = '\0'; | ||
|  | 				printf("<A HREF=\"%s://%s\">%s</A>", (j == 3 ? "ftp" : "http"), | ||
|  | 				       f, f); | ||
|  | 				*g = t; | ||
|  | 				c = g; | ||
|  | 			} else { | ||
|  | 				f[3] = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				c = f + 3; | ||
|  | 				f[3] = '.'; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case 1:	/* mailto */ | ||
|  | 			g = f = idtest[1]; | ||
|  | 			while (g > c && (isalnum(g[-1]) || g[-1] == '_' || g[-1] == '-' || | ||
|  | 			      g[-1] == '+' || g[-1] == '.' || g[-1] == '%')) | ||
|  | 				g--; | ||
|  | 			h = f + 1; | ||
|  | 			while (*h && (isalnum(*h) || *h == '_' || *h == '-' || *h == '+' || | ||
|  | 				      *h == '.')) | ||
|  | 				h++; | ||
|  | 			if (*h == '.') | ||
|  | 				h--; | ||
|  | 			if (h - f > 4 && f - g > 1) { | ||
|  | 				char    t; | ||
|  | 
 | ||
|  | 				t = *g; | ||
|  | 				*g = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				*g = t; | ||
|  | 				t = *h; | ||
|  | 				*h = '\0'; | ||
|  | 				printf("<A HREF=\"mailto:%s\">%s</A>", g, g); | ||
|  | 				*h = t; | ||
|  | 				c = h; | ||
|  | 			} else { | ||
|  | 				*f = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				*f = '@'; | ||
|  | 				idtest[1] = c; | ||
|  | 				c = f; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case 0:	/* url */ | ||
|  | 			g = f = idtest[0]; | ||
|  | 			while (g > c && isalpha(g[-1]) && islower(g[-1])) | ||
|  | 				g--; | ||
|  | 			h = f + 3; | ||
|  | 			while (*h && !isspace(*h) && *h != '<' && *h != '>' && *h != '"' && | ||
|  | 			       *h != '&') | ||
|  | 				h++; | ||
|  | 			if (f - g > 2 && f - g < 7 && h - f > 3) { | ||
|  | 				char    t; | ||
|  | 
 | ||
|  | 				t = *g; | ||
|  | 				*g = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				*g = t; | ||
|  | 				t = *h; | ||
|  | 				*h = '\0'; | ||
|  | 				printf("<A HREF=\"%s\">%s</A>", g, g); | ||
|  | 				*h = t; | ||
|  | 				c = h; | ||
|  | 			} else { | ||
|  | 				f[1] = '\0'; | ||
|  | 				fputs(c, stdout); | ||
|  | 				f[1] = '/'; | ||
|  | 				c = f + 1; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		default: | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		nr = 0; | ||
|  | 		if (idtest[0] && idtest[0] < c) | ||
|  | 			idtest[0] = strstr(c + 1, "://"); | ||
|  | 		if (idtest[1] && idtest[1] < c) | ||
|  | 			idtest[1] = strchr(c + 1, '@'); | ||
|  | 		if (idtest[2] && idtest[2] < c) | ||
|  | 			idtest[2] = strstr(c, "www."); | ||
|  | 		if (idtest[3] && idtest[3] < c) | ||
|  | 			idtest[3] = strstr(c, "ftp."); | ||
|  | 		if (idtest[4] && idtest[4] < c) | ||
|  | 			idtest[4] = strchr(c + 1, '('); | ||
|  | 		if (idtest[5] && idtest[5] < c) | ||
|  | 			idtest[5] = strstr(c + 1, ".h>"); | ||
|  | 		for (i = 0; i < 6; i++) | ||
|  | 			nr += (idtest[i] != NULL); | ||
|  | 	} | ||
|  | 	fputs(c, stdout); | ||
|  | } | ||
|  | 
 | ||
|  | static int current_font = 0; | ||
|  | static int current_size = 0; | ||
|  | static int fillout = 1; | ||
|  | 
 | ||
|  | static void | ||
|  | out_html(char *c) | ||
|  | { | ||
|  | 	if (!c) | ||
|  | 		return; | ||
|  | 	if (no_newline_output) { | ||
|  | 		int     i = 0; | ||
|  | 
 | ||
|  | 		no_newline_output = 1; | ||
|  | 		while (c[i]) { | ||
|  | 			if (!no_newline_output) | ||
|  | 				c[i - 1] = c[i]; | ||
|  | 			if (c[i] == '\n') | ||
|  | 				no_newline_output = 1; | ||
|  | 			i++; | ||
|  | 		} | ||
|  | 		if (!no_newline_output) | ||
|  | 			c[i - 1] = 0; | ||
|  | 	} | ||
|  | 	if (scaninbuff) { | ||
|  | 		while (*c) { | ||
|  | 			if (buffpos >= buffmax) { | ||
|  | 				char   *h; | ||
|  | 
 | ||
|  | 				h = realloc(buffer, buffmax * 2); | ||
|  | 				if (!h) | ||
|  | 					return; | ||
|  | 				buffer = h; | ||
|  | 				buffmax *= 2; | ||
|  | 			} | ||
|  | 			buffer[buffpos++] = *c++; | ||
|  | 		} | ||
|  | 	} else if (output_possible) { | ||
|  | 		while (*c) { | ||
|  | 			outbuffer[obp++] = *c; | ||
|  | 			if (*c == '\n' || obp > HUGE_STR_MAX) { | ||
|  | 				outbuffer[obp] = '\0'; | ||
|  | 				add_links(outbuffer); | ||
|  | 				obp = 0; | ||
|  | 			} | ||
|  | 			c++; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | #define FO0 ""
 | ||
|  | #define FC0 ""
 | ||
|  | #define FO1 "<I>"
 | ||
|  | #define FC1 "</I>"
 | ||
|  | #define FO2 "<B>"
 | ||
|  | #define FC2 "</B>"
 | ||
|  | #define FO3 "<TT>"
 | ||
|  | #define FC3 "</TT>"
 | ||
|  | 
 | ||
|  | static char *switchfont[16] = { | ||
|  | 	"", FC0 FO1, FC0 FO2, FC0 FO3, | ||
|  | 	FC1 FO0, "", FC1 FO2, FC1 FO3, | ||
|  | 	FC2 FO0, FC2 FO1, "", FC2 FO3, | ||
|  | 	FC3 FO0, FC3 FO1, FC3 FO2, "" | ||
|  | }; | ||
|  | 
 | ||
|  | static char * | ||
|  | change_to_font(int nr) | ||
|  | { | ||
|  | 	int     i; | ||
|  | 
 | ||
|  | 	switch (nr) { | ||
|  | 	case '0': | ||
|  | 		nr++; | ||
|  | 	case '1': | ||
|  | 	case '2': | ||
|  | 	case '3': | ||
|  | 	case '4': | ||
|  | 		nr = nr - '1'; | ||
|  | 		break; | ||
|  | 	case V('C', 'W'): | ||
|  | 		nr = 3; | ||
|  | 		break; | ||
|  | 	case 'L': | ||
|  | 		nr = 3; | ||
|  | 		break; | ||
|  | 	case 'B': | ||
|  | 		nr = 2; | ||
|  | 		break; | ||
|  | 	case 'I': | ||
|  | 		nr = 1; | ||
|  | 		break; | ||
|  | 	case 'P': | ||
|  | 	case 'R': | ||
|  | 		nr = 0; | ||
|  | 		break; | ||
|  | 	case 0: | ||
|  | 	case 1: | ||
|  | 	case 2: | ||
|  | 	case 3: | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		nr = 0; | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	i = current_font * 4 + nr % 4; | ||
|  | 	current_font = nr % 4; | ||
|  | 	return switchfont[i]; | ||
|  | } | ||
|  | 
 | ||
|  | static char sizebuf[200]; | ||
|  | 
 | ||
|  | static char * | ||
|  | change_to_size(int nr) | ||
|  | { | ||
|  | 	int     i; | ||
|  | 
 | ||
|  | 	switch (nr) { | ||
|  | 	case '0': | ||
|  | 	case '1': | ||
|  | 	case '2': | ||
|  | 	case '3': | ||
|  | 	case '4': | ||
|  | 	case '5': | ||
|  | 	case '6': | ||
|  | 	case '7': | ||
|  | 	case '8': | ||
|  | 	case '9': | ||
|  | 		nr = nr - '0'; | ||
|  | 		break; | ||
|  | 	case '\0': | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		nr = current_size + nr; | ||
|  | 		if (nr > 9) | ||
|  | 			nr = 9; | ||
|  | 		if (nr < -9) | ||
|  | 			nr = -9; | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	if (nr == current_size) | ||
|  | 		return ""; | ||
|  | 	i = current_font; | ||
|  | 	sizebuf[0] = '\0'; | ||
|  | 	strcat(sizebuf, change_to_font(0)); | ||
|  | 	if (current_size) | ||
|  | 		strcat(sizebuf, "</FONT>"); | ||
|  | 	current_size = nr; | ||
|  | 	if (nr) { | ||
|  | 		int     l; | ||
|  | 
 | ||
|  | 		strcat(sizebuf, "<FONT SIZE="); | ||
|  | 		l = strlen(sizebuf); | ||
|  | 		if (nr > 0) | ||
|  | 			sizebuf[l++] = '+'; | ||
|  | 		else | ||
|  | 			sizebuf[l++] = '-', nr = -nr; | ||
|  | 		sizebuf[l++] = nr + '0'; | ||
|  | 		sizebuf[l++] = '>'; | ||
|  | 		sizebuf[l] = '\0'; | ||
|  | 	} | ||
|  | 	strcat(sizebuf, change_to_font(i)); | ||
|  | 	return sizebuf; | ||
|  | } | ||
|  | 
 | ||
|  | static int asint = 0; | ||
|  | static int intresult = 0; | ||
|  | 
 | ||
|  | #define SKIPEOL while (*c && *c++!='\n')
 | ||
|  | 
 | ||
|  | static int skip_escape = 0; | ||
|  | static int single_escape = 0; | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_escape(char *c) | ||
|  | { | ||
|  | 	char   *h = NULL; | ||
|  | 	char    b[5]; | ||
|  | 	INTDEF *intd; | ||
|  | 	int     exoutputp, exskipescape; | ||
|  | 	int     i, j; | ||
|  | 
 | ||
|  | 	intresult = 0; | ||
|  | 	switch (*c) { | ||
|  | 	case 'e': | ||
|  | 		h = "\\"; | ||
|  | 		curpos++; | ||
|  | 		break; | ||
|  | 	case '0': | ||
|  | 	case ' ': | ||
|  | 		h = " "; | ||
|  | 		curpos++; | ||
|  | 		break; | ||
|  | 	case '|': | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case '"': | ||
|  | 		SKIPEOL; | ||
|  | 		c--; | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case '$': | ||
|  | 		if (argument) { | ||
|  | 			c++; | ||
|  | 			i = (*c - '1'); | ||
|  | 			if (!(h = argument[i])) | ||
|  | 				h = ""; | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case 'z': | ||
|  | 		c++; | ||
|  | 		if (*c == '\\') { | ||
|  | 			c = scan_escape(c + 1); | ||
|  | 			c--; | ||
|  | 			h = ""; | ||
|  | 		} else { | ||
|  | 			b[0] = *c; | ||
|  | 			b[1] = '\0'; | ||
|  | 			h = ""; | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case 'k': | ||
|  | 		c++; | ||
|  | 		if (*c == '(') | ||
|  | 			c += 2; | ||
|  | 	case '^': | ||
|  | 	case '!': | ||
|  | 	case '%': | ||
|  | 	case 'a': | ||
|  | 	case 'd': | ||
|  | 	case 'r': | ||
|  | 	case 'u': | ||
|  | 	case '\n': | ||
|  | 	case '&': | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case '(': | ||
|  | 		c++; | ||
|  | 		i = c[0] * 256 + c[1]; | ||
|  | 		c++; | ||
|  | 		h = expand_char(i); | ||
|  | 		break; | ||
|  | 	case '*': | ||
|  | 		c++; | ||
|  | 		if (*c == '(') { | ||
|  | 			c++; | ||
|  | 			i = c[0] * 256 + c[1]; | ||
|  | 			c++; | ||
|  | 		} else | ||
|  | 			i = *c * 256 + ' '; | ||
|  | 		h = expand_string(i); | ||
|  | 		break; | ||
|  | 	case 'f': | ||
|  | 		c++; | ||
|  | 		if (*c == '\\') { | ||
|  | 			c++; | ||
|  | 			c = scan_escape(c); | ||
|  | 			c--; | ||
|  | 			i = intresult; | ||
|  | 		} else if (*c != '(') | ||
|  | 			i = *c; | ||
|  | 		else { | ||
|  | 			c++; | ||
|  | 			i = c[0] * 256 + c[1]; | ||
|  | 			c++; | ||
|  | 		} | ||
|  | 		if (!skip_escape) | ||
|  | 			h = change_to_font(i); | ||
|  | 		else | ||
|  | 			h = ""; | ||
|  | 		break; | ||
|  | 	case 's': | ||
|  | 		c++; | ||
|  | 		j = 0; | ||
|  | 		i = 0; | ||
|  | 		if (*c == '-') { | ||
|  | 			j = -1; | ||
|  | 			c++; | ||
|  | 		} else if (*c == '+') { | ||
|  | 			j = 1; | ||
|  | 			c++; | ||
|  | 		} | ||
|  | 		if (*c == '0') | ||
|  | 			c++; | ||
|  | 		else if (*c == '\\') { | ||
|  | 			c++; | ||
|  | 			c = scan_escape(c); | ||
|  | 			i = intresult; | ||
|  | 			if (!j) | ||
|  | 				j = 1; | ||
|  | 		} else | ||
|  | 			while (isdigit(*c) && (!i || (!j && i < 4))) | ||
|  | 				i = i * 10 + (*c++) - '0'; | ||
|  | 		if (!j) { | ||
|  | 			j = 1; | ||
|  | 			if (i) | ||
|  | 				i = i - 10; | ||
|  | 		} | ||
|  | 		if (!skip_escape) | ||
|  | 			h = change_to_size(i * j); | ||
|  | 		else | ||
|  | 			h = ""; | ||
|  | 		c--; | ||
|  | 		break; | ||
|  | 	case 'n': | ||
|  | 		c++; | ||
|  | 		j = 0; | ||
|  | 		switch (*c) { | ||
|  | 		case '+': | ||
|  | 			j = 1; | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case '-': | ||
|  | 			j = -1; | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		default: | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		if (*c == '(') { | ||
|  | 			c++; | ||
|  | 			i = V(c[0], c[1]); | ||
|  | 			c = c + 1; | ||
|  | 		} else { | ||
|  | 			i = V(c[0], ' '); | ||
|  | 		} | ||
|  | 		intd = intdef; | ||
|  | 		while (intd && intd->nr != i) | ||
|  | 			intd = intd->next; | ||
|  | 		if (intd) { | ||
|  | 			intd->val = intd->val + j * intd->incr; | ||
|  | 			intresult = intd->val; | ||
|  | 		} else { | ||
|  | 			switch (i) { | ||
|  | 			case V('.', 's'): | ||
|  | 				intresult = current_size; | ||
|  | 				break; | ||
|  | 			case V('.', 'f'): | ||
|  | 				intresult = current_font; | ||
|  | 				break; | ||
|  | 			default: | ||
|  | 				intresult = 0; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case 'w': | ||
|  | 		c++; | ||
|  | 		i = *c; | ||
|  | 		c++; | ||
|  | 		exoutputp = output_possible; | ||
|  | 		exskipescape = skip_escape; | ||
|  | 		output_possible = 0; | ||
|  | 		skip_escape = 1; | ||
|  | 		j = 0; | ||
|  | 		while (*c != i) { | ||
|  | 			j++; | ||
|  | 			if (*c == escapesym) | ||
|  | 				c = scan_escape(c + 1); | ||
|  | 			else | ||
|  | 				c++; | ||
|  | 		} | ||
|  | 		output_possible = exoutputp; | ||
|  | 		skip_escape = exskipescape; | ||
|  | 		intresult = j; | ||
|  | 		break; | ||
|  | 	case 'l': | ||
|  | 		h = "<HR>"; | ||
|  | 		curpos = 0; | ||
|  | 	case 'b': | ||
|  | 	case 'v': | ||
|  | 	case 'x': | ||
|  | 	case 'o': | ||
|  | 	case 'L': | ||
|  | 	case 'h': | ||
|  | 		c++; | ||
|  | 		i = *c; | ||
|  | 		c++; | ||
|  | 		exoutputp = output_possible; | ||
|  | 		exskipescape = skip_escape; | ||
|  | 		output_possible = 0; | ||
|  | 		skip_escape = 1; | ||
|  | 		while (*c != i) | ||
|  | 			if (*c == escapesym) | ||
|  | 				c = scan_escape(c + 1); | ||
|  | 			else | ||
|  | 				c++; | ||
|  | 		output_possible = exoutputp; | ||
|  | 		skip_escape = exskipescape; | ||
|  | 		break; | ||
|  | 	case 'c': | ||
|  | 		no_newline_output = 1; | ||
|  | 		break; | ||
|  | 	case '{': | ||
|  | 		newline_for_fun++; | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case '}': | ||
|  | 		if (newline_for_fun) | ||
|  | 			newline_for_fun--; | ||
|  | 		h = ""; | ||
|  | 		break; | ||
|  | 	case 'p': | ||
|  | 		h = "<BR>\n"; | ||
|  | 		curpos = 0; | ||
|  | 		break; | ||
|  | 	case 't': | ||
|  | 		h = "\t"; | ||
|  | 		curpos = (curpos + 8) & 0xfff8; | ||
|  | 		break; | ||
|  | 	case '<': | ||
|  | 		h = "<"; | ||
|  | 		curpos++; | ||
|  | 		break; | ||
|  | 	case '>': | ||
|  | 		h = ">"; | ||
|  | 		curpos++; | ||
|  | 		break; | ||
|  | 	case '\\': | ||
|  | 		if (single_escape) { | ||
|  | 			c--; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		b[0] = *c; | ||
|  | 		b[1] = 0; | ||
|  | 		h = b; | ||
|  | 		curpos++; | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	c++; | ||
|  | 	if (!skip_escape) | ||
|  | 		out_html(h); | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | typedef struct TABLEITEM TABLEITEM; | ||
|  | 
 | ||
|  | struct TABLEITEM { | ||
|  | 	char   *contents; | ||
|  | 	int     size, align, valign, colspan, rowspan, font, vleft, vright, space, | ||
|  | 	        width; | ||
|  | 	TABLEITEM *next; | ||
|  | }; | ||
|  | 
 | ||
|  | static TABLEITEM emptyfield = {NULL, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, NULL}; | ||
|  | 
 | ||
|  | typedef struct TABLEROW TABLEROW; | ||
|  | 
 | ||
|  | struct TABLEROW { | ||
|  | 	TABLEITEM *first; | ||
|  | 	TABLEROW *prev, *next; | ||
|  | }; | ||
|  | 
 | ||
|  | static char *tableopt[] = { | ||
|  | 	"center", "expand", "box", "allbox", "doublebox", | ||
|  | 	"tab", "linesize", "delim", NULL | ||
|  | }; | ||
|  | static int tableoptl[] = {6, 6, 3, 6, 9, 3, 8, 5, 0}; | ||
|  | 
 | ||
|  | static void | ||
|  | clear_table(TABLEROW * table) | ||
|  | { | ||
|  | 	TABLEROW *tr1, *tr2; | ||
|  | 	TABLEITEM *ti1, *ti2; | ||
|  | 
 | ||
|  | 	tr1 = table; | ||
|  | 	while (tr1->prev) | ||
|  | 		tr1 = tr1->prev; | ||
|  | 	while (tr1) { | ||
|  | 		ti1 = tr1->first; | ||
|  | 		while (ti1) { | ||
|  | 			ti2 = ti1->next; | ||
|  | 			if (ti1->contents) | ||
|  | 				free(ti1->contents); | ||
|  | 			free(ti1); | ||
|  | 			ti1 = ti2; | ||
|  | 		} | ||
|  | 		tr2 = tr1; | ||
|  | 		tr1 = tr1->next; | ||
|  | 		free(tr2); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static char *scan_expression(char *c, int *result); | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_format(char *c, TABLEROW ** result, int *maxcol) | ||
|  | { | ||
|  | 	TABLEROW *layout, *currow; | ||
|  | 	TABLEITEM *curfield; | ||
|  | 	int     i, j; | ||
|  | 
 | ||
|  | 	if (*result) { | ||
|  | 		clear_table(*result); | ||
|  | 	} | ||
|  | 	layout = currow = (TABLEROW *) malloc(sizeof(TABLEROW)); | ||
|  | 	currow->next = currow->prev = NULL; | ||
|  | 	currow->first = curfield = (TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 	*curfield = emptyfield; | ||
|  | 	while (*c && *c != '.') { | ||
|  | 		switch (*c) { | ||
|  | 		case 'C': | ||
|  | 		case 'c': | ||
|  | 		case 'N': | ||
|  | 		case 'n': | ||
|  | 		case 'R': | ||
|  | 		case 'r': | ||
|  | 		case 'A': | ||
|  | 		case 'a': | ||
|  | 		case 'L': | ||
|  | 		case 'l': | ||
|  | 		case 'S': | ||
|  | 		case 's': | ||
|  | 		case '^': | ||
|  | 		case '_': | ||
|  | 			if (curfield->align) { | ||
|  | 				curfield->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 				curfield = curfield->next; | ||
|  | 				*curfield = emptyfield; | ||
|  | 			} | ||
|  | 			curfield->align = toupper(*c); | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case 'i': | ||
|  | 		case 'I': | ||
|  | 		case 'B': | ||
|  | 		case 'b': | ||
|  | 			curfield->font = toupper(*c); | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case 'f': | ||
|  | 		case 'F': | ||
|  | 			c++; | ||
|  | 			curfield->font = toupper(*c); | ||
|  | 			c++; | ||
|  | 			if (!isspace(*c)) | ||
|  | 				c++; | ||
|  | 			break; | ||
|  | 		case 't': | ||
|  | 		case 'T': | ||
|  | 			curfield->valign = 't'; | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case 'p': | ||
|  | 		case 'P': | ||
|  | 			c++; | ||
|  | 			i = j = 0; | ||
|  | 			if (*c == '+') { | ||
|  | 				j = 1; | ||
|  | 				c++; | ||
|  | 			} | ||
|  | 			if (*c == '-') { | ||
|  | 				j = -1; | ||
|  | 				c++; | ||
|  | 			} | ||
|  | 			while (isdigit(*c)) | ||
|  | 				i = i * 10 + (*c++) - '0'; | ||
|  | 			if (j) | ||
|  | 				curfield->size = i * j; | ||
|  | 			else | ||
|  | 				curfield->size = j - 10; | ||
|  | 			break; | ||
|  | 		case 'v': | ||
|  | 		case 'V': | ||
|  | 		case 'w': | ||
|  | 		case 'W': | ||
|  | 			c = scan_expression(c + 2, &curfield->width); | ||
|  | 			break; | ||
|  | 		case '|': | ||
|  | 			if (curfield->align) | ||
|  | 				curfield->vleft++; | ||
|  | 			else | ||
|  | 				curfield->vright++; | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case 'e': | ||
|  | 		case 'E': | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		case '0': | ||
|  | 		case '1': | ||
|  | 		case '2': | ||
|  | 		case '3': | ||
|  | 		case '4': | ||
|  | 		case '5': | ||
|  | 		case '6': | ||
|  | 		case '7': | ||
|  | 		case '8': | ||
|  | 		case '9': | ||
|  | 			i = 0; | ||
|  | 			while (isdigit(*c)) | ||
|  | 				i = i * 10 + (*c++) - '0'; | ||
|  | 			curfield->space = i; | ||
|  | 			break; | ||
|  | 		case ',': | ||
|  | 		case '\n': | ||
|  | 			currow->next = (TABLEROW *) malloc(sizeof(TABLEROW)); | ||
|  | 			currow->next->prev = currow; | ||
|  | 			currow = currow->next; | ||
|  | 			currow->next = NULL; | ||
|  | 			curfield = currow->first = (TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 			*curfield = emptyfield; | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		default: | ||
|  | 			c++; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if (*c == '.') | ||
|  | 		while (*c++ != '\n'); | ||
|  | 	*maxcol = 0; | ||
|  | 	currow = layout; | ||
|  | 	while (currow) { | ||
|  | 		curfield = layout->first; | ||
|  | 		i = 0; | ||
|  | 		while (curfield) { | ||
|  | 			i++; | ||
|  | 			curfield = curfield->next; | ||
|  | 		} | ||
|  | 		if (i > *maxcol) | ||
|  | 			*maxcol = i; | ||
|  | 		currow = currow->next; | ||
|  | 	} | ||
|  | 	*result = layout; | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | static TABLEROW * | ||
|  | next_row(TABLEROW * tr) | ||
|  | { | ||
|  | 	if (tr->next) { | ||
|  | 		tr = tr->next; | ||
|  | 		if (!tr->next) | ||
|  | 			next_row(tr); | ||
|  | 		return tr; | ||
|  | 	} else { | ||
|  | 		TABLEITEM *ti, *ti2; | ||
|  | 
 | ||
|  | 		tr->next = (TABLEROW *) malloc(sizeof(TABLEROW)); | ||
|  | 		tr->next->prev = tr; | ||
|  | 		ti = tr->first; | ||
|  | 		tr = tr->next; | ||
|  | 		tr->next = NULL; | ||
|  | 		if (ti) | ||
|  | 			tr->first = ti2 = (TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 		else | ||
|  | 			tr->first = ti2 = NULL; | ||
|  | 		while (ti != ti2) { | ||
|  | 			*ti2 = *ti; | ||
|  | 			ti2->contents = NULL; | ||
|  | 			if ((ti = ti->next)) { | ||
|  | 				ti2->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 			} | ||
|  | 			ti2 = ti2->next; | ||
|  | 		} | ||
|  | 		return tr; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static char itemreset[20] = "\\fR\\s0"; | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_table(char *c) | ||
|  | { | ||
|  | 	char   *t, *h, *g; | ||
|  | 	int     center = 0, expand = 0, box = 0, border = 0, linesize = 1; | ||
|  | 	int     i, j, maxcol = 0, finished = 0; | ||
|  | 	int     oldfont, oldsize, oldfillout; | ||
|  | 	char    itemsep = '\t'; | ||
|  | 	TABLEROW *layout = NULL, *currow, *ftable; | ||
|  | 	TABLEITEM *curfield; | ||
|  | 
 | ||
|  | 	while (*c++ != '\n'); | ||
|  | 	h = c; | ||
|  | 	if (*h == '.') | ||
|  | 		return c - 1; | ||
|  | 	oldfont = current_font; | ||
|  | 	oldsize = current_size; | ||
|  | 	oldfillout = fillout; | ||
|  | 	out_html(change_to_font(0)); | ||
|  | 	out_html(change_to_size(0)); | ||
|  | 	if (!fillout) { | ||
|  | 		fillout = 1; | ||
|  | 		out_html("</PRE>"); | ||
|  | 	} | ||
|  | 	while (*h && *h != '\n') | ||
|  | 		h++; | ||
|  | 	if (h[-1] == ';') { | ||
|  | 		/* scan table options */ | ||
|  | 		while (c < h) { | ||
|  | 			while (isspace(*c)) | ||
|  | 				c++; | ||
|  | 			for (i = 0; tableopt[i] && strncmp(tableopt[i], c, tableoptl[i]); i++); | ||
|  | 			c = c + tableoptl[i]; | ||
|  | 			switch (i) { | ||
|  | 			case 0: | ||
|  | 				center = 1; | ||
|  | 				break; | ||
|  | 			case 1: | ||
|  | 				expand = 1; | ||
|  | 				break; | ||
|  | 			case 2: | ||
|  | 				box = 1; | ||
|  | 				break; | ||
|  | 			case 3: | ||
|  | 				border = 1; | ||
|  | 				break; | ||
|  | 			case 4: | ||
|  | 				box = 2; | ||
|  | 				break; | ||
|  | 			case 5: | ||
|  | 				while (*c++ != '('); | ||
|  | 				itemsep = *c++; | ||
|  | 				break; | ||
|  | 			case 6: | ||
|  | 				while (*c++ != '('); | ||
|  | 				linesize = 0; | ||
|  | 				while (isdigit(*c)) | ||
|  | 					linesize = linesize * 10 + (*c++) - '0'; | ||
|  | 				break; | ||
|  | 			case 7: | ||
|  | 				while (*c != ')') | ||
|  | 					c++; | ||
|  | 			default: | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			c++; | ||
|  | 		} | ||
|  | 		c = h + 1; | ||
|  | 	} | ||
|  | 	/* scan layout */ | ||
|  | 	c = scan_format(c, &layout, &maxcol); | ||
|  | 	currow = layout; | ||
|  | 	next_row(currow); | ||
|  | 	curfield = layout->first; | ||
|  | 	i = 0; | ||
|  | 	while (!finished) { | ||
|  | 		/* search item */ | ||
|  | 		h = c; | ||
|  | 		if ((*c == '_' || *c == '=') && (c[1] == itemsep || c[1] == '\n')) { | ||
|  | 			if (c[-1] == '\n' && c[1] == '\n') { | ||
|  | 				if (currow->prev) { | ||
|  | 					currow->prev->next = (TABLEROW *) malloc(sizeof(TABLEROW)); | ||
|  | 					currow->prev->next->next = currow; | ||
|  | 					currow->prev->next->prev = currow->prev; | ||
|  | 					currow->prev = currow->prev->next; | ||
|  | 				} else { | ||
|  | 					currow->prev = layout = (TABLEROW *) malloc(sizeof(TABLEROW)); | ||
|  | 					currow->prev->prev = NULL; | ||
|  | 					currow->prev->next = currow; | ||
|  | 				} | ||
|  | 				curfield = currow->prev->first = | ||
|  | 					(TABLEITEM *) malloc(sizeof(TABLEITEM)); | ||
|  | 				*curfield = emptyfield; | ||
|  | 				curfield->align = *c; | ||
|  | 				curfield->colspan = maxcol; | ||
|  | 				curfield = currow->first; | ||
|  | 				c = c + 2; | ||
|  | 			} else { | ||
|  | 				if (curfield) { | ||
|  | 					curfield->align = *c; | ||
|  | 					do { | ||
|  | 						curfield = curfield->next; | ||
|  | 					} while (curfield && curfield->align == 'S'); | ||
|  | 				} | ||
|  | 				if (c[1] == '\n') { | ||
|  | 					currow = next_row(currow); | ||
|  | 					curfield = currow->first; | ||
|  | 				} | ||
|  | 				c = c + 2; | ||
|  | 			} | ||
|  | 		} else if (*c == 'T' && c[1] == '{') { | ||
|  | 			h = c + 2; | ||
|  | 			c = strstr(h, "\nT}"); | ||
|  | 			c++; | ||
|  | 			*c = '\0'; | ||
|  | 			g = NULL; | ||
|  | 			scan_troff(h, 0, &g); | ||
|  | 			scan_troff(itemreset, 0, &g); | ||
|  | 			*c = 'T'; | ||
|  | 			c += 3; | ||
|  | 			if (curfield) { | ||
|  | 				curfield->contents = g; | ||
|  | 				do { | ||
|  | 					curfield = curfield->next; | ||
|  | 				} while (curfield && curfield->align == 'S'); | ||
|  | 			} else if (g) | ||
|  | 				free(g); | ||
|  | 			if (c[-1] == '\n') { | ||
|  | 				currow = next_row(currow); | ||
|  | 				curfield = currow->first; | ||
|  | 			} | ||
|  | 		} else if (*c == '.' && c[1] == 'T' && c[2] == '&' && c[-1] == '\n') { | ||
|  | 			TABLEROW *hr; | ||
|  | 
 | ||
|  | 			while (*c++ != '\n'); | ||
|  | 			hr = currow; | ||
|  | 			currow = currow->prev; | ||
|  | 			hr->prev = NULL; | ||
|  | 			c = scan_format(c, &hr, &i); | ||
|  | 			hr->prev = currow; | ||
|  | 			currow->next = hr; | ||
|  | 			currow = hr; | ||
|  | 			next_row(currow); | ||
|  | 			curfield = currow->first; | ||
|  | 		} else if (*c == '.' && c[1] == 'T' && c[2] == 'E' && c[-1] == '\n') { | ||
|  | 			finished = 1; | ||
|  | 			while (*c++ != '\n'); | ||
|  | 			if (currow->prev) | ||
|  | 				currow->prev->next = NULL; | ||
|  | 			currow->prev = NULL; | ||
|  | 			clear_table(currow); | ||
|  | 		} else if (*c == '.' && c[-1] == '\n' && !isdigit(c[1])) { | ||
|  | 			/*
 | ||
|  | 			 * skip troff request inside table (usually only .sp | ||
|  | 			 * ) | ||
|  | 			 */ | ||
|  | 			while (*c++ != '\n'); | ||
|  | 		} else { | ||
|  | 			h = c; | ||
|  | 			while (*c && (*c != itemsep || c[-1] == '\\') && | ||
|  | 			       (*c != '\n' || c[-1] == '\\')) | ||
|  | 				c++; | ||
|  | 			i = 0; | ||
|  | 			if (*c == itemsep) { | ||
|  | 				i = 1; | ||
|  | 				*c = '\n'; | ||
|  | 			} | ||
|  | 			if (h[0] == '\\' && h[2] == '\n' && | ||
|  | 			    (h[1] == '_' || h[1] == '^')) { | ||
|  | 				if (curfield) { | ||
|  | 					curfield->align = h[1]; | ||
|  | 					do { | ||
|  | 						curfield = curfield->next; | ||
|  | 					} while (curfield && curfield->align == 'S'); | ||
|  | 				} | ||
|  | 				h = h + 3; | ||
|  | 			} else { | ||
|  | 				g = NULL; | ||
|  | 				h = scan_troff(h, 1, &g); | ||
|  | 				scan_troff(itemreset, 0, &g); | ||
|  | 				if (curfield) { | ||
|  | 					curfield->contents = g; | ||
|  | 					do { | ||
|  | 						curfield = curfield->next; | ||
|  | 					} while (curfield && curfield->align == 'S'); | ||
|  | 				} else if (g) | ||
|  | 					free(g); | ||
|  | 			} | ||
|  | 			if (i) | ||
|  | 				*c = itemsep; | ||
|  | 			c = h; | ||
|  | 			if (c[-1] == '\n') { | ||
|  | 				currow = next_row(currow); | ||
|  | 				curfield = currow->first; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	/* calculate colspan and rowspan */ | ||
|  | 	currow = layout; | ||
|  | 	while (currow->next) | ||
|  | 		currow = currow->next; | ||
|  | 	while (currow) { | ||
|  | 		TABLEITEM *ti, *ti1 = NULL, *ti2 = NULL; | ||
|  | 
 | ||
|  | 		ti = currow->first; | ||
|  | 		if (currow->prev) | ||
|  | 			ti1 = currow->prev->first; | ||
|  | 		while (ti) { | ||
|  | 			switch (ti->align) { | ||
|  | 			case 'S': | ||
|  | 				if (ti2) { | ||
|  | 					ti2->colspan++; | ||
|  | 					if (ti2->rowspan < ti->rowspan) | ||
|  | 						ti2->rowspan = ti->rowspan; | ||
|  | 				} | ||
|  | 				break; | ||
|  | 			case '^': | ||
|  | 				if (ti1) | ||
|  | 					ti1->rowspan++; | ||
|  | 			default: | ||
|  | 				if (!ti2) | ||
|  | 					ti2 = ti; | ||
|  | 				else { | ||
|  | 					do { | ||
|  | 						ti2 = ti2->next; | ||
|  | 					} while (ti2 && curfield->align == 'S'); | ||
|  | 				} | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			ti = ti->next; | ||
|  | 			if (ti1) | ||
|  | 				ti1 = ti1->next; | ||
|  | 		} | ||
|  | 		currow = currow->prev; | ||
|  | 	} | ||
|  | 	/* produce html output */ | ||
|  | 	if (center) | ||
|  | 		out_html("<CENTER>"); | ||
|  | 	if (box == 2) | ||
|  | 		out_html("<TABLE BORDER><TR><TD>"); | ||
|  | 	out_html("<TABLE"); | ||
|  | 	if (box || border) { | ||
|  | 		out_html(" BORDER"); | ||
|  | 		if (!border) | ||
|  | 			out_html("><TR><TD><TABLE"); | ||
|  | 		if (expand) | ||
|  | 			out_html(" WIDTH=100%"); | ||
|  | 	} | ||
|  | 	out_html(">\n"); | ||
|  | 	currow = layout; | ||
|  | 	while (currow) { | ||
|  | 		j = 0; | ||
|  | 		out_html("<TR VALIGN=top>"); | ||
|  | 		curfield = currow->first; | ||
|  | 		while (curfield) { | ||
|  | 			if (curfield->align != 'S' && curfield->align != '^') { | ||
|  | 				out_html("<TD"); | ||
|  | 				switch (curfield->align) { | ||
|  | 				case 'N': | ||
|  | 					curfield->space += 4; | ||
|  | 				case 'R': | ||
|  | 					out_html(" ALIGN=right"); | ||
|  | 					break; | ||
|  | 				case 'C': | ||
|  | 					out_html(" ALIGN=center"); | ||
|  | 				default: | ||
|  | 					break; | ||
|  | 				} | ||
|  | 				if (!curfield->valign && curfield->rowspan > 1) | ||
|  | 					out_html(" VALIGN=center"); | ||
|  | 				if (curfield->colspan > 1) { | ||
|  | 					char    buf[5]; | ||
|  | 
 | ||
|  | 					out_html(" COLSPAN="); | ||
|  | 					sprintf(buf, "%i", curfield->colspan); | ||
|  | 					out_html(buf); | ||
|  | 				} | ||
|  | 				if (curfield->rowspan > 1) { | ||
|  | 					char    buf[5]; | ||
|  | 
 | ||
|  | 					out_html(" ROWSPAN="); | ||
|  | 					sprintf(buf, "%i", curfield->rowspan); | ||
|  | 					out_html(buf); | ||
|  | 				} | ||
|  | 				j = j + curfield->colspan; | ||
|  | 				out_html(">"); | ||
|  | 				if (curfield->size) | ||
|  | 					out_html(change_to_size(curfield->size)); | ||
|  | 				if (curfield->font) | ||
|  | 					out_html(change_to_font(curfield->font)); | ||
|  | 				switch (curfield->align) { | ||
|  | 				case '=': | ||
|  | 					out_html("<HR><HR>"); | ||
|  | 					break; | ||
|  | 				case '_': | ||
|  | 					out_html("<HR>"); | ||
|  | 					break; | ||
|  | 				default: | ||
|  | 					if (curfield->contents) | ||
|  | 						out_html(curfield->contents); | ||
|  | 					break; | ||
|  | 				} | ||
|  | 				if (curfield->space) | ||
|  | 					for (i = 0; i < curfield->space; i++) | ||
|  | 						out_html(" "); | ||
|  | 				if (curfield->font) | ||
|  | 					out_html(change_to_font(0)); | ||
|  | 				if (curfield->size) | ||
|  | 					out_html(change_to_size(0)); | ||
|  | 				if (j >= maxcol && curfield->align > '@' && curfield->align != '_') | ||
|  | 					out_html("<BR>"); | ||
|  | 				out_html("</TD>"); | ||
|  | 			} | ||
|  | 			curfield = curfield->next; | ||
|  | 		} | ||
|  | 		out_html("</TR>\n"); | ||
|  | 		currow = currow->next; | ||
|  | 	} | ||
|  | 	if (box && !border) | ||
|  | 		out_html("</TABLE>"); | ||
|  | 	out_html("</TABLE>"); | ||
|  | 	if (box == 2) | ||
|  | 		out_html("</TABLE>"); | ||
|  | 	if (center) | ||
|  | 		out_html("</CENTER>\n"); | ||
|  | 	else | ||
|  | 		out_html("\n"); | ||
|  | 	if (!oldfillout) | ||
|  | 		out_html("<PRE>"); | ||
|  | 	fillout = oldfillout; | ||
|  | 	out_html(change_to_size(oldsize)); | ||
|  | 	out_html(change_to_font(oldfont)); | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_expression(char *c, int *result) | ||
|  | { | ||
|  | 	int     value = 0, value2, j = 0, sign = 1, opex = 0; | ||
|  | 	char    oper = 'c'; | ||
|  | 
 | ||
|  | 	if (*c == '!') { | ||
|  | 		c = scan_expression(c + 1, &value); | ||
|  | 		value = (!value); | ||
|  | 	} else if (*c == 'n') { | ||
|  | 		c++; | ||
|  | 		value = NROFF; | ||
|  | 	} else if (*c == 't') { | ||
|  | 		c++; | ||
|  | 		value = 1 - NROFF; | ||
|  | 	} else if (*c == '\'' || *c == '"' || *c < ' ' || (*c == '\\' && c[1] == '(')) { | ||
|  | 		/*
 | ||
|  | 		 * ?string1?string2? test if string1 equals string2. | ||
|  | 		 */ | ||
|  | 		char   *st1 = NULL, *st2 = NULL, *h; | ||
|  | 		char   *tcmp = NULL; | ||
|  | 		char    sep; | ||
|  | 
 | ||
|  | 		sep = *c; | ||
|  | 		if (sep == '\\') { | ||
|  | 			tcmp = c; | ||
|  | 			c = c + 3; | ||
|  | 		} | ||
|  | 		c++; | ||
|  | 		h = c; | ||
|  | 		while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) | ||
|  | 			c++; | ||
|  | 		*c = '\n'; | ||
|  | 		scan_troff(h, 1, &st1); | ||
|  | 		*c = sep; | ||
|  | 		if (tcmp) | ||
|  | 			c = c + 3; | ||
|  | 		c++; | ||
|  | 		h = c; | ||
|  | 		while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) | ||
|  | 			c++; | ||
|  | 		*c = '\n'; | ||
|  | 		scan_troff(h, 1, &st2); | ||
|  | 		*c = sep; | ||
|  | 		if (!st1 && !st2) | ||
|  | 			value = 1; | ||
|  | 		else if (!st1 || !st2) | ||
|  | 			value = 0; | ||
|  | 		else | ||
|  | 			value = (!strcmp(st1, st2)); | ||
|  | 		if (st1) | ||
|  | 			free(st1); | ||
|  | 		if (st2) | ||
|  | 			free(st2); | ||
|  | 		if (tcmp) | ||
|  | 			c = c + 3; | ||
|  | 		c++; | ||
|  | 	} else { | ||
|  | 		while (*c && !isspace(*c) && *c != ')') { | ||
|  | 			opex = 0; | ||
|  | 			switch (*c) { | ||
|  | 			case '(': | ||
|  | 				c = scan_expression(c + 1, &value2); | ||
|  | 				value2 = sign * value2; | ||
|  | 				opex = 1; | ||
|  | 				break; | ||
|  | 			case '.': | ||
|  | 			case '0': | ||
|  | 			case '1': | ||
|  | 			case '2': | ||
|  | 			case '3': | ||
|  | 			case '4': | ||
|  | 			case '5': | ||
|  | 			case '6': | ||
|  | 			case '7': | ||
|  | 			case '8': | ||
|  | 			case '9':{ | ||
|  | 					int     num = 0, denum = 1; | ||
|  | 
 | ||
|  | 					value2 = 0; | ||
|  | 					while (isdigit(*c)) | ||
|  | 						value2 = value2 * 10 + ((*c++) - '0'); | ||
|  | 					if (*c == '.') { | ||
|  | 						c++; | ||
|  | 						while (isdigit(*c)) { | ||
|  | 							num = num * 10 + ((*c++) - '0'); | ||
|  | 							denum = denum * 10; | ||
|  | 						} | ||
|  | 					} | ||
|  | 					if (isalpha(*c)) { | ||
|  | 						/* scale indicator */ | ||
|  | 						switch (*c) { | ||
|  | 						case 'i':	/* inch -> 10pt */ | ||
|  | 							value2 = value2 * 10 + (num * 10 + denum / 2) / denum; | ||
|  | 							num = 0; | ||
|  | 							break; | ||
|  | 						default: | ||
|  | 							break; | ||
|  | 						} | ||
|  | 						c++; | ||
|  | 					} | ||
|  | 					value2 = value2 + (num + denum / 2) / denum; | ||
|  | 					value2 = sign * value2; | ||
|  | 					opex = 1; | ||
|  | 					break; | ||
|  | 				} | ||
|  | 			case '\\': | ||
|  | 				c = scan_escape(c + 1); | ||
|  | 				value2 = intresult * sign; | ||
|  | 				if (isalpha(*c)) | ||
|  | 					c++;	/* scale indicator */ | ||
|  | 				opex = 1; | ||
|  | 				break; | ||
|  | 			case '-': | ||
|  | 				if (oper) { | ||
|  | 					sign = -1; | ||
|  | 					c++; | ||
|  | 					break; | ||
|  | 				} | ||
|  | 			case '>': | ||
|  | 			case '<': | ||
|  | 			case '+': | ||
|  | 			case '/': | ||
|  | 			case '*': | ||
|  | 			case '%': | ||
|  | 			case '&': | ||
|  | 			case '=': | ||
|  | 			case ':': | ||
|  | 				if (c[1] == '=') | ||
|  | 					oper = (*c++) + 16; | ||
|  | 				else | ||
|  | 					oper = *c; | ||
|  | 				c++; | ||
|  | 				break; | ||
|  | 			default: | ||
|  | 				c++; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			if (opex) { | ||
|  | 				sign = 1; | ||
|  | 				switch (oper) { | ||
|  | 				case 'c': | ||
|  | 					value = value2; | ||
|  | 					break; | ||
|  | 				case '-': | ||
|  | 					value = value - value2; | ||
|  | 					break; | ||
|  | 				case '+': | ||
|  | 					value = value + value2; | ||
|  | 					break; | ||
|  | 				case '*': | ||
|  | 					value = value * value2; | ||
|  | 					break; | ||
|  | 				case '/': | ||
|  | 					if (value2) | ||
|  | 						value = value / value2; | ||
|  | 					break; | ||
|  | 				case '%': | ||
|  | 					if (value2) | ||
|  | 						value = value % value2; | ||
|  | 					break; | ||
|  | 				case '<': | ||
|  | 					value = (value < value2); | ||
|  | 					break; | ||
|  | 				case '>': | ||
|  | 					value = (value > value2); | ||
|  | 					break; | ||
|  | 				case '>' + 16: | ||
|  | 					value = (value >= value2); | ||
|  | 					break; | ||
|  | 				case '<' + 16: | ||
|  | 					value = (value <= value2); | ||
|  | 					break; | ||
|  | 				case '=': | ||
|  | 				case '=' + 16: | ||
|  | 					value = (value == value2); | ||
|  | 					break; | ||
|  | 				case '&': | ||
|  | 					value = (value && value2); | ||
|  | 					break; | ||
|  | 				case ':': | ||
|  | 					value = (value || value2); | ||
|  | 					break; | ||
|  | 				default: | ||
|  | 					fprintf(stderr, "man2html: unknown operator %c.\n", oper); | ||
|  | 				} | ||
|  | 				oper = 0; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		if (*c == ')') | ||
|  | 			c++; | ||
|  | 	} | ||
|  | 	*result = value; | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | static void | ||
|  | trans_char(char *c, char s, char t) | ||
|  | { | ||
|  | 	char   *sl = c; | ||
|  | 	int     slash = 0; | ||
|  | 
 | ||
|  | 	while (*sl != '\n' || slash) { | ||
|  | 		if (!slash) { | ||
|  | 			if (*sl == escapesym) | ||
|  | 				slash = 1; | ||
|  | 			else if (*sl == s) | ||
|  | 				*sl = t; | ||
|  | 		} else | ||
|  | 			slash = 0; | ||
|  | 		sl++; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | fill_words(char *c, char *words[], int *n) | ||
|  | { | ||
|  | 	char   *sl = c; | ||
|  | 	int     slash = 0; | ||
|  | 	int     skipspace = 0; | ||
|  | 
 | ||
|  | 	*n = 0; | ||
|  | 	words[*n] = sl; | ||
|  | 	while (*sl && (*sl != '\n' || slash)) { | ||
|  | 		if (!slash) { | ||
|  | 			if (*sl == '"') { | ||
|  | 				*sl = '\a'; | ||
|  | 				skipspace = !skipspace; | ||
|  | 			} else if (*sl == escapesym) | ||
|  | 				slash = 1; | ||
|  | 			else if ((*sl == ' ' || *sl == '\t') && !skipspace) { | ||
|  | 				*sl = '\n'; | ||
|  | 				if (words[*n] != sl) | ||
|  | 					(*n)++; | ||
|  | 				words[*n] = sl + 1; | ||
|  | 			} | ||
|  | 		} else { | ||
|  | 			if (*sl == '"') { | ||
|  | 				sl--; | ||
|  | 				*sl = '\n'; | ||
|  | 				if (words[*n] != sl) | ||
|  | 					(*n)++; | ||
|  | 				sl++; | ||
|  | 				while (*sl && *sl != '\n') | ||
|  | 					sl++; | ||
|  | 				words[*n] = sl; | ||
|  | 				sl--; | ||
|  | 			} | ||
|  | 			slash = 0; | ||
|  | 		} | ||
|  | 		sl++; | ||
|  | 	} | ||
|  | 	if (sl != words[*n]) | ||
|  | 		(*n)++; | ||
|  | 	return sl; | ||
|  | } | ||
|  | 
 | ||
|  | static char *abbrev_list[] = { | ||
|  | 	"GSBG", "Getting Started ", | ||
|  | 	"SUBG", "Customizing SunOS", | ||
|  | 	"SHBG", "Basic Troubleshooting", | ||
|  | 	"SVBG", "SunView User's Guide", | ||
|  | 	"MMBG", "Mail and Messages", | ||
|  | 	"DMBG", "Doing More with SunOS", | ||
|  | 	"UNBG", "Using the Network", | ||
|  | 	"GDBG", "Games, Demos & Other Pursuits", | ||
|  | 	"CHANGE", "SunOS 4.1 Release Manual", | ||
|  | 	"INSTALL", "Installing SunOS 4.1", | ||
|  | 	"ADMIN", "System and Network Administration", | ||
|  | 	"SECUR", "Security Features Guide", | ||
|  | 	"PROM", "PROM User's Manual", | ||
|  | 	"DIAG", "Sun System Diagnostics", | ||
|  | 	"SUNDIAG", "Sundiag User's Guide", | ||
|  | 	"MANPAGES", "SunOS Reference Manual", | ||
|  | 	"REFMAN", "SunOS Reference Manual", | ||
|  | 	"SSI", "Sun System Introduction", | ||
|  | 	"SSO", "System Services Overview", | ||
|  | 	"TEXT", "Editing Text Files", | ||
|  | 	"DOCS", "Formatting Documents", | ||
|  | 	"TROFF", "Using <B>nroff</B> and <B>troff</B>", | ||
|  | 	"INDEX", "Global Index", | ||
|  | 	"CPG", "C Programmer's Guide", | ||
|  | 	"CREF", "C Reference Manual", | ||
|  | 	"ASSY", "Assembly Language Reference", | ||
|  | 	"PUL", "Programming Utilities and Libraries", | ||
|  | 	"DEBUG", "Debugging Tools", | ||
|  | 	"NETP", "Network Programming", | ||
|  | 	"DRIVER", "Writing Device Drivers", | ||
|  | 	"STREAMS", "STREAMS Programming", | ||
|  | 	"SBDK", "SBus Developer's Kit", | ||
|  | 	"WDDS", "Writing Device Drivers for the SBus", | ||
|  | 	"FPOINT", "Floating-Point Programmer's Guide", | ||
|  | 	"SVPG", "SunView 1 Programmer's Guide", | ||
|  | 	"SVSPG", "SunView 1 System Programmer's Guide", | ||
|  | 	"PIXRCT", "Pixrect Reference Manual", | ||
|  | 	"CGI", "SunCGI Reference Manual", | ||
|  | 	"CORE", "SunCore Reference Manual", | ||
|  | 	"4ASSY", "Sun-4 Assembly Language Reference", | ||
|  | 	"SARCH", "<FONT SIZE=-1>SPARC</FONT> Architecture Manual", | ||
|  | 	"KR", "The C Programming Language", | ||
|  | NULL, NULL}; | ||
|  | 
 | ||
|  | static char * | ||
|  | lookup_abbrev(char *c) | ||
|  | { | ||
|  | 	int     i = 0; | ||
|  | 
 | ||
|  | 	if (!c) | ||
|  | 		return ""; | ||
|  | 	while (abbrev_list[i] && strcmp(c, abbrev_list[i])) | ||
|  | 		i = i + 2; | ||
|  | 	if (abbrev_list[i]) | ||
|  | 		return abbrev_list[i + 1]; | ||
|  | 	else | ||
|  | 		return c; | ||
|  | } | ||
|  | 
 | ||
|  | static char manidx[NULL_TERMINATED(HUGE_STR_MAX)]; | ||
|  | static int subs = 0; | ||
|  | static int mip = 0; | ||
|  | static char label[5] = "lbAA"; | ||
|  | 
 | ||
|  | static void | ||
|  | add_to_index(int level, char *item) | ||
|  | { | ||
|  | 	char   *c = NULL; | ||
|  | 
 | ||
|  | 	label[3]++; | ||
|  | 	if (label[3] > 'Z') { | ||
|  | 		label[3] = 'A'; | ||
|  | 		label[2]++; | ||
|  | 	} | ||
|  | 	if (level != subs) { | ||
|  | 		if (subs) { | ||
|  | 			strmaxcpy(manidx + mip, "</DL>\n", HUGE_STR_MAX - mip); | ||
|  | 			mip += 6; | ||
|  | 		} else { | ||
|  | 			strmaxcpy(manidx + mip, "<DL>\n", HUGE_STR_MAX - mip); | ||
|  | 			mip += 5; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	subs = level; | ||
|  | 	scan_troff(item, 1, &c); | ||
|  | 	sprintf(manidx + mip, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label, c); | ||
|  | 	if (c) | ||
|  | 		free(c); | ||
|  | 	while (manidx[mip]) | ||
|  | 		mip++; | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | skip_till_newline(char *c) | ||
|  | { | ||
|  | 	int     lvl = 0; | ||
|  | 
 | ||
|  | 	while (*c && *c != '\n' || lvl > 0) { | ||
|  | 		if (*c == '\\') { | ||
|  | 			c++; | ||
|  | 			if (*c == '}') | ||
|  | 				lvl--; | ||
|  | 			else if (*c == '{') | ||
|  | 				lvl++; | ||
|  | 		} | ||
|  | 		c++; | ||
|  | 	} | ||
|  | 	c++; | ||
|  | 	if (lvl < 0 && newline_for_fun) { | ||
|  | 		newline_for_fun = newline_for_fun + lvl; | ||
|  | 		if (newline_for_fun < 0) | ||
|  | 			newline_for_fun = 0; | ||
|  | 	} | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | static int ifelseval = 0; | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_request(char *c) | ||
|  | { | ||
|  | 	/* BSD Mandoc stuff */ | ||
|  | 	static int mandoc_synopsis = 0;	/* True if we are in the synopsis
 | ||
|  | 					 * section */ | ||
|  | 	static int mandoc_command = 0;	/* True if this is mandoc page */ | ||
|  | 	static int mandoc_bd_options;	/* Only copes with non-nested Bd's */ | ||
|  | 
 | ||
|  | 	int     i, j, mode = 0; | ||
|  | 	char   *h; | ||
|  | 	char   *wordlist[MAX_WORDLIST]; | ||
|  | 	int     words; | ||
|  | 	char   *sl; | ||
|  | 	STRDEF *owndef; | ||
|  | 
 | ||
|  | 	while (*c == ' ' || *c == '\t') | ||
|  | 		c++; | ||
|  | 	if (c[0] == '\n') | ||
|  | 		return c + 1; | ||
|  | 	if (c[1] == '\n') | ||
|  | 		j = 1; | ||
|  | 	else | ||
|  | 		j = 2; | ||
|  | 	while (c[j] == ' ' || c[j] == '\t') | ||
|  | 		j++; | ||
|  | 	if (c[0] == escapesym) { | ||
|  | 		/* some pages use .\" .\$1 .\} */ | ||
|  | 		/* .\$1 is too difficult/stuppid */ | ||
|  | 		if (c[1] == '$') | ||
|  | 			c = skip_till_newline(c); | ||
|  | 		else | ||
|  | 			c = scan_escape(c + 1); | ||
|  | 	} else { | ||
|  | 		i = V(c[0], c[1]); | ||
|  | 		switch (i) { | ||
|  | 		case V('a', 'b'): | ||
|  | 			h = c + j; | ||
|  | 			while (*h && *h != '\n') | ||
|  | 				h++; | ||
|  | 			*h = '\0'; | ||
|  | 			if (scaninbuff && buffpos) { | ||
|  | 				buffer[buffpos] = '\0'; | ||
|  | 				puts(buffer); | ||
|  | 			} | ||
|  | 			/* fprintf(stderr, "%s\n", c+2); */ | ||
|  | 			exit(0); | ||
|  | 			break; | ||
|  | 		case V('d', 'i'): | ||
|  | 			{ | ||
|  | 				STRDEF *de; | ||
|  | 				int     oldcurpos = curpos; | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				i = V(c[0], c[1]); | ||
|  | 				if (*c == '\n') { | ||
|  | 					c++; | ||
|  | 					break; | ||
|  | 				} | ||
|  | 				while (*c && *c != '\n') | ||
|  | 					c++; | ||
|  | 				c++; | ||
|  | 				h = c; | ||
|  | 				while (*c && strncmp(c, ".di", 3)) | ||
|  | 					while (*c && *c++ != '\n'); | ||
|  | 				*c = '\0'; | ||
|  | 				de = strdef; | ||
|  | 				while (de && de->nr != i) | ||
|  | 					de = de->next; | ||
|  | 				if (!de) { | ||
|  | 					de = (STRDEF *) malloc(sizeof(STRDEF)); | ||
|  | 					de->nr = i; | ||
|  | 					de->slen = 0; | ||
|  | 					de->next = strdef; | ||
|  | 					de->st = NULL; | ||
|  | 					strdef = de; | ||
|  | 				} else { | ||
|  | 					if (de->st) | ||
|  | 						free(de->st); | ||
|  | 					de->slen = 0; | ||
|  | 					de->st = NULL; | ||
|  | 				} | ||
|  | 				scan_troff(h, 0, &de->st); | ||
|  | 				*c = '.'; | ||
|  | 				while (*c && *c++ != '\n'); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('d', 's'): | ||
|  | 			mode = 1; | ||
|  | 		case V('a', 's'): | ||
|  | 			{ | ||
|  | 				STRDEF *de; | ||
|  | 				int     oldcurpos = curpos; | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				i = V(c[0], c[1]); | ||
|  | 				j = 0; | ||
|  | 				while (c[j] && c[j] != '\n') | ||
|  | 					j++; | ||
|  | 				if (j < 3) { | ||
|  | 					c = c + j; | ||
|  | 					break; | ||
|  | 				} | ||
|  | 				if (c[1] == ' ') | ||
|  | 					c = c + 1; | ||
|  | 				else | ||
|  | 					c = c + 2; | ||
|  | 				while (isspace(*c)) | ||
|  | 					c++; | ||
|  | 				if (*c == '"') | ||
|  | 					c++; | ||
|  | 				de = strdef; | ||
|  | 				while (de && de->nr != i) | ||
|  | 					de = de->next; | ||
|  | 				single_escape = 1; | ||
|  | 				curpos = 0; | ||
|  | 				if (!de) { | ||
|  | 					char   *h; | ||
|  | 
 | ||
|  | 					de = (STRDEF *) malloc(sizeof(STRDEF)); | ||
|  | 					de->nr = i; | ||
|  | 					de->slen = 0; | ||
|  | 					de->next = strdef; | ||
|  | 					de->st = NULL; | ||
|  | 					strdef = de; | ||
|  | 					h = NULL; | ||
|  | 					c = scan_troff(c, 1, &h); | ||
|  | 					de->st = h; | ||
|  | 					de->slen = curpos; | ||
|  | 				} else { | ||
|  | 					if (mode) { | ||
|  | 						char   *h = NULL; | ||
|  | 
 | ||
|  | 						c = scan_troff(c, 1, &h); | ||
|  | 						free(de->st); | ||
|  | 						de->slen = 0; | ||
|  | 						de->st = h; | ||
|  | 					} else | ||
|  | 						c = scan_troff(c, 1, &de->st); | ||
|  | 					de->slen += curpos; | ||
|  | 				} | ||
|  | 				single_escape = 0; | ||
|  | 				curpos = oldcurpos; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case V('b', 'r'): | ||
|  | 			if (still_dd) | ||
|  | 				out_html("<DD>"); | ||
|  | 			else | ||
|  | 				out_html("<BR>\n"); | ||
|  | 			curpos = 0; | ||
|  | 			c = c + j; | ||
|  | 			if (c[0] == escapesym) { | ||
|  | 				c = scan_escape(c + 1); | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('c', '2'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c != '\n') { | ||
|  | 				nobreaksym = *c; | ||
|  | 			} else | ||
|  | 				nobreaksym = '\''; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('c', 'c'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c != '\n') { | ||
|  | 				controlsym = *c; | ||
|  | 			} else | ||
|  | 				controlsym = '.'; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('c', 'e'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') { | ||
|  | 				i = 1; | ||
|  | 			} else { | ||
|  | 				i = 0; | ||
|  | 				while ('0' <= *c && *c <= '9') { | ||
|  | 					i = i * 10 + *c - '0'; | ||
|  | 					c++; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			/* center next i lines */ | ||
|  | 			if (i > 0) { | ||
|  | 				out_html("<CENTER>\n"); | ||
|  | 				while (i && *c) { | ||
|  | 					char   *line = NULL; | ||
|  | 
 | ||
|  | 					c = scan_troff(c, 1, &line); | ||
|  | 					if (line && strncmp(line, "<BR>", 4)) { | ||
|  | 						out_html(line); | ||
|  | 						out_html("<BR>\n"); | ||
|  | 						i--; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				out_html("</CENTER>\n"); | ||
|  | 				curpos = 0; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case V('e', 'c'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c != '\n') { | ||
|  | 				escapesym = *c; | ||
|  | 			} else | ||
|  | 				escapesym = '\\'; | ||
|  | 			break; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 		case V('e', 'o'): | ||
|  | 			escapesym = '\0'; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('e', 'x'): | ||
|  | 			exit(0); | ||
|  | 			break; | ||
|  | 		case V('f', 'c'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') { | ||
|  | 				fieldsym = padsym = '\0'; | ||
|  | 			} else { | ||
|  | 				fieldsym = c[0]; | ||
|  | 				padsym = c[1]; | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('f', 'i'): | ||
|  | 			if (!fillout) { | ||
|  | 				out_html(change_to_font(0)); | ||
|  | 				out_html(change_to_size('0')); | ||
|  | 				out_html("</PRE>\n"); | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			fillout = 1; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('f', 't'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') { | ||
|  | 				out_html(change_to_font(0)); | ||
|  | 			} else { | ||
|  | 				if (*c == escapesym) { | ||
|  | 					int     fn; | ||
|  | 
 | ||
|  | 					c = scan_expression(c, &fn); | ||
|  | 					c--; | ||
|  | 					out_html(change_to_font(fn)); | ||
|  | 				} else { | ||
|  | 					out_html(change_to_font(*c)); | ||
|  | 					c++; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('e', 'l'): | ||
|  | 			/* .el anything : else part of if else */ | ||
|  | 			if (ifelseval) { | ||
|  | 				c = c + j; | ||
|  | 				c[-1] = '\n'; | ||
|  | 				c = scan_troff(c, 1, NULL); | ||
|  | 			} else | ||
|  | 				c = skip_till_newline(c + j); | ||
|  | 			break; | ||
|  | 		case V('i', 'e'): | ||
|  | 			/* .ie c anything : then part of if else */ | ||
|  | 		case V('i', 'f'): | ||
|  | 			/*
 | ||
|  | 			 * .if c anything .if !c anything .if N anything .if | ||
|  | 			 * !N anything .if 'string1'string2' anything .if | ||
|  | 			 * !'string1'string2' anything | ||
|  | 			 */ | ||
|  | 			c = c + j; | ||
|  | 			c = scan_expression(c, &i); | ||
|  | 			ifelseval = !i; | ||
|  | 			if (i) { | ||
|  | 				*c = '\n'; | ||
|  | 				c++; | ||
|  | 				c = scan_troff(c, 1, NULL); | ||
|  | 			} else | ||
|  | 				c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('i', 'g'): | ||
|  | 			{ | ||
|  | 				char   *endwith = "..\n"; | ||
|  | 
 | ||
|  | 				i = 3; | ||
|  | 				c = c + j; | ||
|  | 				if (*c != '\n') { | ||
|  | 					endwith = c - 1; | ||
|  | 					i = 1; | ||
|  | 					c[-1] = '.'; | ||
|  | 					while (*c && *c != '\n') | ||
|  | 						c++, i++; | ||
|  | 				} | ||
|  | 				c++; | ||
|  | 				while (*c && strncmp(c, endwith, i)) | ||
|  | 					while (*c++ != '\n'); | ||
|  | 				while (*c++ != '\n'); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('n', 'f'): | ||
|  | 			if (fillout) { | ||
|  | 				out_html(change_to_font(0)); | ||
|  | 				out_html(change_to_size('0')); | ||
|  | 				out_html("<PRE>\n"); | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			fillout = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('p', 's'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') { | ||
|  | 				out_html(change_to_size('0')); | ||
|  | 			} else { | ||
|  | 				j = 0; | ||
|  | 				i = 0; | ||
|  | 				if (*c == '-') { | ||
|  | 					j = -1; | ||
|  | 					c++; | ||
|  | 				} else if (*c == '+') { | ||
|  | 					j = 1; | ||
|  | 					c++; | ||
|  | 				} | ||
|  | 				c = scan_expression(c, &i); | ||
|  | 				if (!j) { | ||
|  | 					j = 1; | ||
|  | 					if (i > 5) | ||
|  | 						i = i - 10; | ||
|  | 				} | ||
|  | 				out_html(change_to_size(i * j)); | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('s', 'p'): | ||
|  | 			c = c + j; | ||
|  | 			if (fillout) | ||
|  | 				out_html("<P>"); | ||
|  | 			else { | ||
|  | 				out_html(NEWLINE); | ||
|  | 				NEWLINE[0] = '\n'; | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('s', 'o'): | ||
|  | 			{ | ||
|  | 				FILE   *f; | ||
|  | 				struct stat stbuf; | ||
|  | 				int     l = 0; | ||
|  | 				char   *buf; | ||
|  | 				char   *name = NULL; | ||
|  | 
 | ||
|  | 				curpos = 0; | ||
|  | 				c = c + j; | ||
|  | 				if (*c == '/') { | ||
|  | 					h = c; | ||
|  | 				} else { | ||
|  | 					h = c - 3; | ||
|  | 					h[0] = '.'; | ||
|  | 					h[1] = '.'; | ||
|  | 					h[2] = '/'; | ||
|  | 				} | ||
|  | 				while (*c != '\n') | ||
|  | 					c++; | ||
|  | 				*c = '\0'; | ||
|  | 				scan_troff(h, 1, &name); | ||
|  | 				if (name[3] == '/') | ||
|  | 					h = name + 3; | ||
|  | 				else | ||
|  | 					h = name; | ||
|  | 				if (stat(h, &stbuf) != -1) | ||
|  | 					l = stbuf.st_size; | ||
|  | 				buf = stralloc(l + 4); | ||
|  | #if NOCGI
 | ||
|  | 				if (!out_length) { | ||
|  | 					char   *t, *s; | ||
|  | 
 | ||
|  | 					t = strrchr(fname, '/'); | ||
|  | 					if (!t) | ||
|  | 						t = fname; | ||
|  | 					fprintf(stderr, "ln -s %s.html %s.html\n", h, t); | ||
|  | 					s = strrchr(t, '.'); | ||
|  | 					if (!s) | ||
|  | 						s = t; | ||
|  | 					printf("<HTML><HEAD><TITLE> Manpage of %s</TITLE>\n" | ||
|  | 					       "</HEAD><BODY>\n" | ||
|  | 					       "See the manpage for <A HREF=\"%s.html\">%s</A>.\n" | ||
|  | 					       "</BODY></HTML>\n", | ||
|  | 					       s, h, h); | ||
|  | 				} else | ||
|  | #endif
 | ||
|  | 				{ | ||
|  | 					/*
 | ||
|  | 					 * this works alright, except for | ||
|  | 					 * section 3 | ||
|  | 					 */ | ||
|  | 					buf = read_man_page(h); | ||
|  | 					if (!buf) { | ||
|  | 
 | ||
|  | 						fprintf(stderr, "man2html: unable to open or read file %s.\n", | ||
|  | 							h); | ||
|  | 						out_html("<BLOCKQUOTE>" | ||
|  | 							 "man2html: unable to open or read file.\n"); | ||
|  | 						out_html(h); | ||
|  | 						out_html("</BLOCKQUOTE>\n"); | ||
|  | 					} else { | ||
|  | 						buf[0] = buf[l] = '\n'; | ||
|  | 						buf[l + 1] = buf[l + 2] = '\0'; | ||
|  | 						scan_troff(buf + 1, 0, NULL); | ||
|  | 					} | ||
|  | 					if (buf) | ||
|  | 						free(buf); | ||
|  | 				} | ||
|  | 				*c++ = '\n'; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('t', 'a'): | ||
|  | 			c = c + j; | ||
|  | 			j = 0; | ||
|  | 			while (*c != '\n') { | ||
|  | 				sl = scan_expression(c, &tabstops[j]); | ||
|  | 				if (*c == '-' || *c == '+') | ||
|  | 					tabstops[j] += tabstops[j - 1]; | ||
|  | 				c = sl; | ||
|  | 				while (*c == ' ' || *c == '\t') | ||
|  | 					c++; | ||
|  | 				j++; | ||
|  | 			} | ||
|  | 			maxtstop = j; | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('t', 'i'): | ||
|  | 			/*
 | ||
|  | 			 * while (itemdepth || dl_set[itemdepth]) { | ||
|  | 			 * out_html("</DL>\n"); if (dl_set[itemdepth]) | ||
|  | 			 * dl_set[itemdepth]=0; else itemdepth--; } | ||
|  | 			 */ | ||
|  | 			out_html("<BR>\n"); | ||
|  | 			c = c + j; | ||
|  | 			c = scan_expression(c, &j); | ||
|  | 			for (i = 0; i < j; i++) | ||
|  | 				out_html(" "); | ||
|  | 			curpos = j; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('t', 'm'): | ||
|  | 			c = c + j; | ||
|  | 			h = c; | ||
|  | 			while (*c != '\n') | ||
|  | 				c++; | ||
|  | 			*c = '\0'; | ||
|  | 			/* fprintf(stderr,"%s\n", h); */ | ||
|  | 			*c = '\n'; | ||
|  | 			break; | ||
|  | 		case V('B', ' '): | ||
|  | 		case V('B', '\n'): | ||
|  | 		case V('I', ' '): | ||
|  | 		case V('I', '\n'): | ||
|  | 			/* parse one line in a certain font */ | ||
|  | 			out_html(change_to_font(*c)); | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('O', 'P'):	/* groff manpages use this
 | ||
|  | 					 * construction */ | ||
|  | 			/* .OP a b : [ <B>a</B> <I>b</I> ] */ | ||
|  | 			mode = 1; | ||
|  | 			c[0] = 'B'; | ||
|  | 			c[1] = 'I'; | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("["); | ||
|  | 			curpos++; | ||
|  | 		case V('B', 'R'): | ||
|  | 		case V('B', 'I'): | ||
|  | 		case V('I', 'B'): | ||
|  | 		case V('I', 'R'): | ||
|  | 		case V('R', 'B'): | ||
|  | 		case V('R', 'I'): | ||
|  | 			{ | ||
|  | 				char    font[2]; | ||
|  | 
 | ||
|  | 				font[0] = c[0]; | ||
|  | 				font[1] = c[1]; | ||
|  | 				c = c + j; | ||
|  | 				if (*c == '\n') | ||
|  | 					c++; | ||
|  | 				sl = fill_words(c, wordlist, &words); | ||
|  | 				c = sl + 1; | ||
|  | 				/*
 | ||
|  | 				 * .BR name (section) indicates a link. It | ||
|  | 				 * will be added in the output routine. | ||
|  | 				 */ | ||
|  | 				for (i = 0; i < words; i++) { | ||
|  | 					if (mode) { | ||
|  | 						out_html(" "); | ||
|  | 						curpos++; | ||
|  | 					} | ||
|  | 					wordlist[i][-1] = ' '; | ||
|  | 					out_html(change_to_font(font[i & 1])); | ||
|  | 					scan_troff(wordlist[i], 1, NULL); | ||
|  | 				} | ||
|  | 				out_html(change_to_font('R')); | ||
|  | 				if (mode) { | ||
|  | 					out_html(" ]"); | ||
|  | 					curpos++; | ||
|  | 				} | ||
|  | 				out_html(NEWLINE); | ||
|  | 				if (!fillout) | ||
|  | 					curpos = 0; | ||
|  | 				else | ||
|  | 					curpos++; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case V('D', 'T'): | ||
|  | 			for (j = 0; j < 20; j++) | ||
|  | 				tabstops[j] = (j + 1) * 8; | ||
|  | 			maxtstop = 20; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('I', 'P'): | ||
|  | 			sl = fill_words(c + j, wordlist, &words); | ||
|  | 			c = sl + 1; | ||
|  | 			if (!dl_set[itemdepth]) { | ||
|  | 				out_html("<DL COMPACT>\n"); | ||
|  | 				dl_set[itemdepth] = 1; | ||
|  | 			} | ||
|  | 			out_html("<DT>"); | ||
|  | 			if (words) { | ||
|  | 				scan_troff(wordlist[0], 1, NULL); | ||
|  | 			} | ||
|  | 			out_html("<DD>"); | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('T', 'P'): | ||
|  | 			if (!dl_set[itemdepth]) { | ||
|  | 				out_html("<DL COMPACT>\n"); | ||
|  | 				dl_set[itemdepth] = 1; | ||
|  | 			} | ||
|  | 			out_html("<DT>"); | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			/* somewhere a definition ends with '.TP' */ | ||
|  | 			if (!*c) | ||
|  | 				still_dd = 1; | ||
|  | 			else { | ||
|  | 				c = scan_troff(c, 1, NULL); | ||
|  | 				out_html("<DD>"); | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('I', 'X'): | ||
|  | 			/* general index */ | ||
|  | 			sl = fill_words(c + j, wordlist, &words); | ||
|  | 			c = sl + 1; | ||
|  | 			j = 4; | ||
|  | 			while (idxlabel[j] == 'Z') | ||
|  | 				idxlabel[j--] = 'A'; | ||
|  | 			idxlabel[j]++; | ||
|  | #ifdef MAKEINDEX
 | ||
|  | 			fprintf(idxfile, "%s@%s@", fname, idxlabel); | ||
|  | 			for (j = 0; j < words; j++) { | ||
|  | 				h = NULL; | ||
|  | 				scan_troff(wordlist[j], 1, &h); | ||
|  | 				fprintf(idxfile, "_\b@%s", h); | ||
|  | 				free(h); | ||
|  | 			} | ||
|  | 			fprintf(idxfile, "\n"); | ||
|  | #endif
 | ||
|  | 			out_html("<A NAME=\""); | ||
|  | 			out_html(idxlabel); | ||
|  | 			/*
 | ||
|  | 			 * this will not work in mosaic (due to a bug). | ||
|  | 			 * Adding ' ' between '>' and '<' solves it, but | ||
|  | 			 * creates some space. A normal space does not work. | ||
|  | 			 */ | ||
|  | 			out_html("\"></A>"); | ||
|  | 			break; | ||
|  | 		case V('L', 'P'): | ||
|  | 		case V('P', 'P'): | ||
|  | 			if (dl_set[itemdepth]) { | ||
|  | 				out_html("</DL>\n"); | ||
|  | 				dl_set[itemdepth] = 0; | ||
|  | 			} | ||
|  | 			if (fillout) | ||
|  | 				out_html("<P>\n"); | ||
|  | 			else { | ||
|  | 				out_html(NEWLINE); | ||
|  | 				NEWLINE[0] = '\n'; | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('H', 'P'): | ||
|  | 			if (!dl_set[itemdepth]) { | ||
|  | 				out_html("<DL COMPACT>"); | ||
|  | 				dl_set[itemdepth] = 1; | ||
|  | 			} | ||
|  | 			out_html("<DT>\n"); | ||
|  | 			still_dd = 1; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('P', 'D'): | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('R', 's'):	/* BSD mandoc */ | ||
|  | 		case V('R', 'S'): | ||
|  | 			sl = fill_words(c + j, wordlist, &words); | ||
|  | 			j = 1; | ||
|  | 			if (words > 0) | ||
|  | 				scan_expression(wordlist[0], &j); | ||
|  | 			if (j >= 0) { | ||
|  | 				itemdepth++; | ||
|  | 				dl_set[itemdepth] = 0; | ||
|  | 				out_html("<DL COMPACT><DT><DD>"); | ||
|  | 				c = skip_till_newline(c); | ||
|  | 				curpos = 0; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('R', 'e'):	/* BSD mandoc */ | ||
|  | 		case V('R', 'E'): | ||
|  | 			if (itemdepth > 0) { | ||
|  | 				if (dl_set[itemdepth]) | ||
|  | 					out_html("</DL>"); | ||
|  | 				out_html("</DL>\n"); | ||
|  | 				itemdepth--; | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('S', 'B'): | ||
|  | 			out_html(change_to_size(-1)); | ||
|  | 			out_html(change_to_font('B')); | ||
|  | 			c = scan_troff(c + j, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(change_to_size('0')); | ||
|  | 			break; | ||
|  | 		case V('S', 'M'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html(change_to_size(-1)); | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = scan_troff(c, 1, NULL); | ||
|  | 			out_html(change_to_size('0')); | ||
|  | 			break; | ||
|  | 		case V('S', 's'):	/* BSD mandoc */ | ||
|  | 			mandoc_command = 1; | ||
|  | 		case V('S', 'S'): | ||
|  | 			mode = 1; | ||
|  | 		case V('S', 'h'):	/* BSD mandoc */ | ||
|  | 			/* hack for fallthru from above */ | ||
|  | 			mandoc_command = !mode || mandoc_command; | ||
|  | 		case V('S', 'H'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			while (itemdepth || dl_set[itemdepth]) { | ||
|  | 				out_html("</DL>\n"); | ||
|  | 				if (dl_set[itemdepth]) | ||
|  | 					dl_set[itemdepth] = 0; | ||
|  | 				else if (itemdepth > 0) | ||
|  | 					itemdepth--; | ||
|  | 			} | ||
|  | 			out_html(change_to_font(0)); | ||
|  | 			out_html(change_to_size(0)); | ||
|  | 			if (!fillout) { | ||
|  | 				fillout = 1; | ||
|  | 				out_html("</PRE>"); | ||
|  | 			} | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			add_to_index(mode, c); | ||
|  | 			out_html("<A NAME=\""); | ||
|  | 			out_html(label); | ||
|  | 			/*   for mosaic users */ | ||
|  | 			if (mode) | ||
|  | 				out_html("\"> </A>\n<H3>"); | ||
|  | 			else | ||
|  | 				out_html("\"> </A>\n<H2>"); | ||
|  | 			mandoc_synopsis = strncmp(c, "SYNOPSIS", 8) == 0; | ||
|  | 			c = mandoc_command ? scan_troff_mandoc(c, 1, NULL) : scan_troff(c, 1, NULL); | ||
|  | 			if (mode) | ||
|  | 				out_html("</H3>\n"); | ||
|  | 			else | ||
|  | 				out_html("</H2>\n"); | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('T', 'S'): | ||
|  | 			c = scan_table(c); | ||
|  | 			break; | ||
|  | 		case V('D', 't'):	/* BSD mandoc */ | ||
|  | 			mandoc_command = 1; | ||
|  | 		case V('T', 'H'): | ||
|  | 			if (!output_possible) { | ||
|  | 				sl = fill_words(c + j, wordlist, &words); | ||
|  | 				if (words > 1) { | ||
|  | 					char    page_and_sec[128]; | ||
|  | 
 | ||
|  | 					for (i = 1; i < words; i++) | ||
|  | 						wordlist[i][-1] = '\0'; | ||
|  | 					*sl = '\0'; | ||
|  | 					output_possible = 1; | ||
|  | 					sprintf(page_and_sec, "%s(%s)", wordlist[0], wordlist[1]); | ||
|  | 					out_html("<HTML><HEAD>\n<TITLE>"); | ||
|  | 					out_html(page_and_sec); | ||
|  | 					out_html(" Manual Page"); | ||
|  | 					out_html("</TITLE>\n</HEAD>\n<BODY>"); | ||
|  | 					out_html("<TABLE WIDTH=100%>\n"); | ||
|  | 					out_html("<TH ALIGN=LEFT>"); | ||
|  | 					out_html(page_and_sec); | ||
|  | 					out_html("<TH ALIGN=CENTER>"); | ||
|  | 					out_html(wordlist[2]); | ||
|  | 					out_html("<TH ALIGN=RIGHT>"); | ||
|  | 					out_html(page_and_sec); | ||
|  | 					out_html("\n</TABLE>\n"); | ||
|  | 					out_html("<BR><A HREF=\"#index\">Index</A>\n"); | ||
|  | 					*sl = '\n'; | ||
|  | 					out_html("<HR>\n"); | ||
|  | 					if (mandoc_command) | ||
|  | 						out_html("<BR>BSD mandoc<BR>"); | ||
|  | 				} | ||
|  | 				c = sl + 1; | ||
|  | 			} else | ||
|  | 				c = skip_till_newline(c); | ||
|  | 			curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('T', 'X'): | ||
|  | 			sl = fill_words(c + j, wordlist, &words); | ||
|  | 			*sl = '\0'; | ||
|  | 			out_html(change_to_font('I')); | ||
|  | 			if (words > 1) | ||
|  | 				wordlist[1][-1] = '\0'; | ||
|  | 			c = lookup_abbrev(wordlist[0]); | ||
|  | 			curpos += strlen(c); | ||
|  | 			out_html(c); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			if (words > 1) | ||
|  | 				out_html(wordlist[1]); | ||
|  | 			*sl = '\n'; | ||
|  | 			c = sl + 1; | ||
|  | 			break; | ||
|  | 		case V('r', 'm'): | ||
|  | 			/* .rm xx : Remove request, macro or string */ | ||
|  | 		case V('r', 'n'): | ||
|  | 			/*
 | ||
|  | 			 * .rn xx yy : Rename request, macro or string xx to | ||
|  | 			 * yy | ||
|  | 			 */ | ||
|  | 			{ | ||
|  | 				STRDEF *de; | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				i = V(c[0], c[1]); | ||
|  | 				c = c + 2; | ||
|  | 				while (isspace(*c) && *c != '\n') | ||
|  | 					c++; | ||
|  | 				j = V(c[0], c[1]); | ||
|  | 				while (*c && *c != '\n') | ||
|  | 					c++; | ||
|  | 				c++; | ||
|  | 				de = strdef; | ||
|  | 				while (de && de->nr != j) | ||
|  | 					de = de->next; | ||
|  | 				if (de) { | ||
|  | 					if (de->st) | ||
|  | 						free(de->st); | ||
|  | 					de->nr = 0; | ||
|  | 				} | ||
|  | 				de = strdef; | ||
|  | 				while (de && de->nr != i) | ||
|  | 					de = de->next; | ||
|  | 				if (de) | ||
|  | 					de->nr = j; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('n', 'x'): | ||
|  | 			/* .nx filename : next file. */ | ||
|  | 		case V('i', 'n'): | ||
|  | 			/* .in +-N : Indent */ | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('n', 'r'): | ||
|  | 			/*
 | ||
|  | 			 * .nr R +-N M: define and set number register R by | ||
|  | 			 * +-N; auto-increment by M | ||
|  | 			 */ | ||
|  | 			{ | ||
|  | 				INTDEF *intd; | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				i = V(c[0], c[1]); | ||
|  | 				c = c + 2; | ||
|  | 				intd = intdef; | ||
|  | 				while (intd && intd->nr != i) | ||
|  | 					intd = intd->next; | ||
|  | 				if (!intd) { | ||
|  | 					intd = (INTDEF *) malloc(sizeof(INTDEF)); | ||
|  | 					intd->nr = i; | ||
|  | 					intd->val = 0; | ||
|  | 					intd->incr = 0; | ||
|  | 					intd->next = intdef; | ||
|  | 					intdef = intd; | ||
|  | 				} | ||
|  | 				while (*c == ' ' || *c == '\t') | ||
|  | 					c++; | ||
|  | 				c = scan_expression(c, &intd->val); | ||
|  | 				if (*c != '\n') { | ||
|  | 					while (*c == ' ' || *c == '\t') | ||
|  | 						c++; | ||
|  | 					c = scan_expression(c, &intd->incr); | ||
|  | 				} | ||
|  | 				c = skip_till_newline(c); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('a', 'm'): | ||
|  | 			/* .am xx yy : append to a macro. */ | ||
|  | 			/* define or handle as .ig yy */ | ||
|  | 			mode = 1; | ||
|  | 		case V('d', 'e'): | ||
|  | 			/*
 | ||
|  | 			 * .de xx yy : define or redefine macro xx; end at | ||
|  | 			 * .yy (..) | ||
|  | 			 */ | ||
|  | 			/* define or handle as .ig yy */ | ||
|  | 			{ | ||
|  | 				STRDEF *de; | ||
|  | 				int     olen = 0; | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				sl = fill_words(c, wordlist, &words); | ||
|  | 				i = V(c[0], c[1]); | ||
|  | 				j = 2; | ||
|  | 				if (words == 1) | ||
|  | 					wordlist[1] = ".."; | ||
|  | 				else { | ||
|  | 					wordlist[1]--; | ||
|  | 					wordlist[1][0] = '.'; | ||
|  | 					j = 3; | ||
|  | 				} | ||
|  | 				c = sl + 1; | ||
|  | 				sl = c; | ||
|  | 				while (*c && strncmp(c, wordlist[1], j)) | ||
|  | 					c = skip_till_newline(c); | ||
|  | 				de = defdef; | ||
|  | 				while (de && de->nr != i) | ||
|  | 					de = de->next; | ||
|  | 				if (mode && de) | ||
|  | 					olen = strlen(de->st); | ||
|  | 				j = olen + c - sl; | ||
|  | 				h = stralloc(j * 2 + 4); | ||
|  | 				if (h) { | ||
|  | 					for (j = 0; j < olen; j++) | ||
|  | 						h[j] = de->st[j]; | ||
|  | 					if (!j || h[j - 1] != '\n') | ||
|  | 						h[j++] = '\n'; | ||
|  | 					while (sl != c) { | ||
|  | 						if (sl[0] == '\\' && sl[1] == '\\') { | ||
|  | 							h[j++] = '\\'; | ||
|  | 							sl++; | ||
|  | 						} else | ||
|  | 							h[j++] = *sl; | ||
|  | 						sl++; | ||
|  | 					} | ||
|  | 					h[j] = '\0'; | ||
|  | 					if (de) { | ||
|  | 						if (de->st) | ||
|  | 							free(de->st); | ||
|  | 						de->st = h; | ||
|  | 					} else { | ||
|  | 						de = (STRDEF *) malloc(sizeof(STRDEF)); | ||
|  | 						de->nr = i; | ||
|  | 						de->next = defdef; | ||
|  | 						de->st = h; | ||
|  | 						defdef = de; | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('B', 'l'):	/* BSD mandoc */ | ||
|  | 			{ | ||
|  | 				char    list_options[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 				char   *nl = strchr(c, '\n'); | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				if (dl_set[itemdepth]) {	/* These things can
 | ||
|  | 								 * nest. */ | ||
|  | 					itemdepth++; | ||
|  | 				} | ||
|  | 				if (nl) {	/* Parse list options */ | ||
|  | 					strlimitcpy(list_options, c, nl - c, MED_STR_MAX); | ||
|  | 				} | ||
|  | 				if (strstr(list_options, "-bullet")) {	/* HTML Unnumbered List */ | ||
|  | 					dl_set[itemdepth] = BL_BULLET_LIST; | ||
|  | 					out_html("<UL>\n"); | ||
|  | 				} else if (strstr(list_options, "-enum")) {	/* HTML Ordered List */ | ||
|  | 					dl_set[itemdepth] = BL_ENUM_LIST; | ||
|  | 					out_html("<OL>\n"); | ||
|  | 				} else {	/* HTML Descriptive List */ | ||
|  | 					dl_set[itemdepth] = BL_DESC_LIST; | ||
|  | 					out_html("<DL COMPACT>\n"); | ||
|  | 				} | ||
|  | 				if (fillout) | ||
|  | 					out_html("<P>\n"); | ||
|  | 				else { | ||
|  | 					out_html(NEWLINE); | ||
|  | 					NEWLINE[0] = '\n'; | ||
|  | 				} | ||
|  | 				curpos = 0; | ||
|  | 				c = skip_till_newline(c); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('E', 'l'):	/* BSD mandoc */ | ||
|  | 			c = c + j; | ||
|  | 			if (dl_set[itemdepth] & BL_DESC_LIST) { | ||
|  | 				out_html("</DL>\n"); | ||
|  | 			} else if (dl_set[itemdepth] & BL_BULLET_LIST) { | ||
|  | 				out_html("</UL>\n"); | ||
|  | 			} else if (dl_set[itemdepth] & BL_ENUM_LIST) { | ||
|  | 				out_html("</OL>\n"); | ||
|  | 			} | ||
|  | 			dl_set[itemdepth] = 0; | ||
|  | 			if (itemdepth > 0) | ||
|  | 				itemdepth--; | ||
|  | 			if (fillout) | ||
|  | 				out_html("<P>\n"); | ||
|  | 			else { | ||
|  | 				out_html(NEWLINE); | ||
|  | 				NEWLINE[0] = '\n'; | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('I', 't'):	/* BSD mandoc */ | ||
|  | 			c = c + j; | ||
|  | 			if (strncmp(c, "Xo", 2) == 0 && isspace(*(c + 2))) { | ||
|  | 				c = skip_till_newline(c); | ||
|  | 			} | ||
|  | 			if (dl_set[itemdepth] & BL_DESC_LIST) { | ||
|  | 				out_html("<DT>"); | ||
|  | 				out_html(change_to_font('B')); | ||
|  | 				if (*c == '\n') {	/* Don't allow embedded
 | ||
|  | 							 * comms after a newline */ | ||
|  | 					c++; | ||
|  | 					c = scan_troff(c, 1, NULL); | ||
|  | 				} else {	/* Do allow embedded comms on
 | ||
|  | 						 * the same line. */ | ||
|  | 					c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 				} | ||
|  | 				out_html(change_to_font('R')); | ||
|  | 				out_html(NEWLINE); | ||
|  | 				out_html("<DD>"); | ||
|  | 			} else if (dl_set[itemdepth] & (BL_BULLET_LIST | BL_ENUM_LIST)) { | ||
|  | 				out_html("<LI>"); | ||
|  | 				c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 				out_html(NEWLINE); | ||
|  | 			} | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('B', 'k'):	/* BSD mandoc */ | ||
|  | 		case V('E', 'k'):	/* BSD mandoc */ | ||
|  | 		case V('D', 'd'):	/* BSD mandoc */ | ||
|  | 		case V('O', 's'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('B', 't'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			out_html(" is currently in beta test."); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('B', 'x'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html("BSD "); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('D', 'l'):	/* BSD mandoc */ | ||
|  | 			c = c + j; | ||
|  | 			out_html(NEWLINE); | ||
|  | 			out_html("<BLOCKQUOTE>"); | ||
|  | 			out_html(change_to_font('L')); | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("</BLOCKQUOTE>"); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('B', 'd'):	/* BSD mandoc */ | ||
|  | 			{	/* Seems like a kind of example/literal mode */ | ||
|  | 				char    bd_options[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 				char   *nl = strchr(c, '\n'); | ||
|  | 
 | ||
|  | 				c = c + j; | ||
|  | 				if (nl) { | ||
|  | 					strlimitcpy(bd_options, c, nl - c, MED_STR_MAX); | ||
|  | 				} | ||
|  | 				out_html(NEWLINE); | ||
|  | 				mandoc_bd_options = 0;	/* Remember options for
 | ||
|  | 							 * terminating Bl */ | ||
|  | 				if (strstr(bd_options, "-offset indent")) { | ||
|  | 					mandoc_bd_options |= BD_INDENT; | ||
|  | 					out_html("<BLOCKQUOTE>\n"); | ||
|  | 				} | ||
|  | 				if (strstr(bd_options, "-literal") | ||
|  | 				    || strstr(bd_options, "-unfilled")) { | ||
|  | 					if (fillout) { | ||
|  | 						mandoc_bd_options |= BD_LITERAL; | ||
|  | 						out_html(change_to_font(0)); | ||
|  | 						out_html(change_to_size('0')); | ||
|  | 						out_html("<PRE>\n"); | ||
|  | 					} | ||
|  | 					curpos = 0; | ||
|  | 					fillout = 0; | ||
|  | 				} | ||
|  | 				c = skip_till_newline(c); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('E', 'd'):	/* BSD mandoc */ | ||
|  | 			if (mandoc_bd_options & BD_LITERAL) { | ||
|  | 				if (!fillout) { | ||
|  | 					out_html(change_to_font(0)); | ||
|  | 					out_html(change_to_size('0')); | ||
|  | 					out_html("</PRE>\n"); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (mandoc_bd_options & BD_INDENT) | ||
|  | 				out_html("</BLOCKQUOTE>\n"); | ||
|  | 			curpos = 0; | ||
|  | 			fillout = 1; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('B', 'e'):	/* BSD mandoc */ | ||
|  | 			c = c + j; | ||
|  | 			if (fillout) | ||
|  | 				out_html("<P>"); | ||
|  | 			else { | ||
|  | 				out_html(NEWLINE); | ||
|  | 				NEWLINE[0] = '\n'; | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('X', 'r'):	/* BSD mandoc */ | ||
|  | 			{ | ||
|  | 				/*
 | ||
|  | 				 * Translate xyz 1 to xyz(1) Allow for | ||
|  | 				 * multiple spaces.  Allow the section to be | ||
|  | 				 * missing. | ||
|  | 				 */ | ||
|  | 				char    buff[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 				char   *bufptr; | ||
|  | 
 | ||
|  | 				trans_char(c, '"', '\a'); | ||
|  | 				bufptr = buff; | ||
|  | 				c = c + j; | ||
|  | 				if (*c == '\n') | ||
|  | 					c++;	/* Skip spaces */ | ||
|  | 				while (isspace(*c) && *c != '\n') | ||
|  | 					c++; | ||
|  | 				while (isalnum(*c)) {	/* Copy the xyz part */ | ||
|  | 					*bufptr = *c; | ||
|  | 					bufptr++; | ||
|  | 					if (bufptr >= buff + MED_STR_MAX) | ||
|  | 						break; | ||
|  | 					c++; | ||
|  | 				} | ||
|  | 				while (isspace(*c) && *c != '\n') | ||
|  | 					c++;	/* Skip spaces */ | ||
|  | 				if (isdigit(*c)) {	/* Convert the number if
 | ||
|  | 							 * there is one */ | ||
|  | 					*bufptr = '('; | ||
|  | 					bufptr++; | ||
|  | 					if (bufptr < buff + MED_STR_MAX) { | ||
|  | 						while (isalnum(*c)) { | ||
|  | 							*bufptr = *c; | ||
|  | 							bufptr++; | ||
|  | 							if (bufptr >= buff + MED_STR_MAX) | ||
|  | 								break; | ||
|  | 							c++; | ||
|  | 						} | ||
|  | 						if (bufptr < buff + MED_STR_MAX) { | ||
|  | 							*bufptr = ')'; | ||
|  | 							bufptr++; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				while (*c != '\n') {	/* Copy the remainder */ | ||
|  | 					if (!isspace(*c)) { | ||
|  | 						*bufptr = *c; | ||
|  | 						bufptr++; | ||
|  | 						if (bufptr >= buff + MED_STR_MAX) | ||
|  | 							break; | ||
|  | 					} | ||
|  | 					c++; | ||
|  | 				} | ||
|  | 				*bufptr = '\n'; | ||
|  | 				scan_troff_mandoc(buff, 1, NULL); | ||
|  | 
 | ||
|  | 				out_html(NEWLINE); | ||
|  | 				if (fillout) | ||
|  | 					curpos++; | ||
|  | 				else | ||
|  | 					curpos = 0; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case V('F', 'l'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			out_html("-"); | ||
|  | 			if (*c != '\n') { | ||
|  | 				out_html(change_to_font('B')); | ||
|  | 				c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 				out_html(change_to_font('R')); | ||
|  | 			} | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('P', 'a'):	/* BSD mandoc */ | ||
|  | 		case V('P', 'f'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('P', 'p'):	/* BSD mandoc */ | ||
|  | 			if (fillout) | ||
|  | 				out_html("<P>\n"); | ||
|  | 			else { | ||
|  | 				out_html(NEWLINE); | ||
|  | 				NEWLINE[0] = '\n'; | ||
|  | 			} | ||
|  | 			curpos = 0; | ||
|  | 			c = skip_till_newline(c); | ||
|  | 			break; | ||
|  | 		case V('D', 'q'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html("``"); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html("''"); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('O', 'p'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("["); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("]"); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('O', 'o'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("["); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('O', 'c'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html("]"); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('P', 'q'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html("("); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(")"); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('Q', 'l'):	/* BSD mandoc */ | ||
|  | 			{	/* Single quote first word in the line */ | ||
|  | 				char   *sp; | ||
|  | 
 | ||
|  | 				trans_char(c, '"', '\a'); | ||
|  | 				c = c + j; | ||
|  | 				if (*c == '\n') | ||
|  | 					c++; | ||
|  | 				sp = c; | ||
|  | 				do {	/* Find first whitespace after the
 | ||
|  | 					 * first word that isn't a mandoc | ||
|  | 					 * macro */ | ||
|  | 					while (*sp && isspace(*sp)) | ||
|  | 						sp++; | ||
|  | 					while (*sp && !isspace(*sp)) | ||
|  | 						sp++; | ||
|  | 				} while (*sp && isupper(*(sp - 2)) && islower(*(sp - 1))); | ||
|  | 
 | ||
|  | 				/*
 | ||
|  | 				 * Use a newline to mark the end of text to | ||
|  | 				 * be quoted | ||
|  | 				 */ | ||
|  | 				if (*sp) | ||
|  | 					*sp = '\n'; | ||
|  | 				out_html("`");	/* Quote the text */ | ||
|  | 				c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 				out_html("'"); | ||
|  | 				out_html(NEWLINE); | ||
|  | 				if (fillout) | ||
|  | 					curpos++; | ||
|  | 				else | ||
|  | 					curpos = 0; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('S', 'q'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html("`"); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html("'"); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('A', 'r'):	/* BSD mandoc */ | ||
|  | 			/* parse one line in italics */ | ||
|  | 			out_html(change_to_font('I')); | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') {	/* An empty Ar means "file
 | ||
|  | 						 * ..." */ | ||
|  | 				out_html("file ..."); | ||
|  | 			} else { | ||
|  | 				c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			} | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('A', 'd'):	/* BSD mandoc */ | ||
|  | 		case V('E', 'm'):	/* BSD mandoc */ | ||
|  | 		case V('V', 'a'):	/* BSD mandoc */ | ||
|  | 		case V('X', 'c'):	/* BSD mandoc */ | ||
|  | 			/* parse one line in italics */ | ||
|  | 			out_html(change_to_font('I')); | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('N', 'd'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html(" - "); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('N', 'm'):	/* BSD mandoc */ | ||
|  | 			{ | ||
|  | 				static char mandoc_name[NULL_TERMINATED(SMALL_STR_MAX)] = ""; | ||
|  | 
 | ||
|  | 				trans_char(c, '"', '\a'); | ||
|  | 				c = c + j; | ||
|  | 				if (mandoc_synopsis) {	/* Break lines only in
 | ||
|  | 							 * the Synopsis. The | ||
|  | 							 * Synopsis section | ||
|  | 							 * seems to be treated | ||
|  | 							 * as a special case - | ||
|  | 							 * Bummer! */ | ||
|  | 					static int count = 0;	/* Don't break on the
 | ||
|  | 								 * first Nm */ | ||
|  | 
 | ||
|  | 					if (count) { | ||
|  | 						out_html("<BR>"); | ||
|  | 					} else { | ||
|  | 						char   *end = strchr(c, '\n'); | ||
|  | 
 | ||
|  | 						if (end) {	/* Remember the name for
 | ||
|  | 								 * later. */ | ||
|  | 							strlimitcpy(mandoc_name, c, end - c, SMALL_STR_MAX); | ||
|  | 						} | ||
|  | 					} | ||
|  | 					count++; | ||
|  | 				} | ||
|  | 				out_html(change_to_font('B')); | ||
|  | 				while (*c == ' ' || *c == '\t') | ||
|  | 					c++; | ||
|  | 				if (*c == '\n') {	/* If Nm has no
 | ||
|  | 							 * argument, use one | ||
|  | 							 * from an earlier Nm | ||
|  | 							 * command that did have | ||
|  | 							 * one.  Hope there | ||
|  | 							 * aren't too many | ||
|  | 							 * commands that do | ||
|  | 							 * this. */ | ||
|  | 					out_html(mandoc_name); | ||
|  | 				} else { | ||
|  | 					c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 				} | ||
|  | 				out_html(change_to_font('R')); | ||
|  | 				out_html(NEWLINE); | ||
|  | 				if (fillout) | ||
|  | 					curpos++; | ||
|  | 				else | ||
|  | 					curpos = 0; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		case V('C', 'd'):	/* BSD mandoc */ | ||
|  | 		case V('C', 'm'):	/* BSD mandoc */ | ||
|  | 		case V('I', 'c'):	/* BSD mandoc */ | ||
|  | 		case V('M', 's'):	/* BSD mandoc */ | ||
|  | 		case V('O', 'r'):	/* BSD mandoc */ | ||
|  | 		case V('S', 'y'):	/* BSD mandoc */ | ||
|  | 			/* parse one line in bold */ | ||
|  | 			out_html(change_to_font('B')); | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('D', 'v'):	/* BSD mandoc */ | ||
|  | 		case V('E', 'v'):	/* BSD mandoc */ | ||
|  | 		case V('F', 'r'):	/* BSD mandoc */ | ||
|  | 		case V('L', 'i'):	/* BSD mandoc */ | ||
|  | 		case V('N', 'o'):	/* BSD mandoc */ | ||
|  | 		case V('N', 's'):	/* BSD mandoc */ | ||
|  | 		case V('T', 'n'):	/* BSD mandoc */ | ||
|  | 		case V('n', 'N'):	/* BSD mandoc */ | ||
|  | 			trans_char(c, '"', '\a'); | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			out_html(change_to_font('B')); | ||
|  | 			c = scan_troff_mandoc(c, 1, NULL); | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			out_html(NEWLINE); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('%', 'A'):	/* BSD mandoc biblio stuff */ | ||
|  | 		case V('%', 'D'): | ||
|  | 		case V('%', 'N'): | ||
|  | 		case V('%', 'O'): | ||
|  | 		case V('%', 'P'): | ||
|  | 		case V('%', 'Q'): | ||
|  | 		case V('%', 'V'): | ||
|  | 			c = c + j; | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff(c, 1, NULL);	/* Don't allow embedded
 | ||
|  | 							 * mandoc coms */ | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		case V('%', 'B'): | ||
|  | 		case V('%', 'J'): | ||
|  | 		case V('%', 'R'): | ||
|  | 		case V('%', 'T'): | ||
|  | 			c = c + j; | ||
|  | 			out_html(change_to_font('I')); | ||
|  | 			if (*c == '\n') | ||
|  | 				c++; | ||
|  | 			c = scan_troff(c, 1, NULL);	/* Don't allow embedded
 | ||
|  | 							 * mandoc coms */ | ||
|  | 			out_html(change_to_font('R')); | ||
|  | 			if (fillout) | ||
|  | 				curpos++; | ||
|  | 			else | ||
|  | 				curpos = 0; | ||
|  | 			break; | ||
|  | 		default: | ||
|  | 			/* search macro database of self-defined macros */ | ||
|  | 			owndef = defdef; | ||
|  | 			while (owndef && owndef->nr != i) | ||
|  | 				owndef = owndef->next; | ||
|  | 			if (owndef) { | ||
|  | 				char  **oldargument; | ||
|  | 				int     deflen; | ||
|  | 				int     onff; | ||
|  | 
 | ||
|  | 				sl = fill_words(c + j, wordlist, &words); | ||
|  | 				c = sl + 1; | ||
|  | 				*sl = '\0'; | ||
|  | 				for (i = 1; i < words; i++) | ||
|  | 					wordlist[i][-1] = '\0'; | ||
|  | 				for (i = 0; i < words; i++) { | ||
|  | 					char   *h = NULL; | ||
|  | 
 | ||
|  | 					if (mandoc_command) { | ||
|  | 						scan_troff_mandoc(wordlist[i], 1, &h); | ||
|  | 					} else { | ||
|  | 						scan_troff(wordlist[i], 1, &h); | ||
|  | 					} | ||
|  | 					wordlist[i] = h; | ||
|  | 				} | ||
|  | 				for (i = words; i < 20; i++) | ||
|  | 					wordlist[i] = NULL; | ||
|  | 				deflen = strlen(owndef->st); | ||
|  | 				for (i = 0; owndef->st[deflen + 2 + i] = owndef->st[i]; i++); | ||
|  | 				oldargument = argument; | ||
|  | 				argument = wordlist; | ||
|  | 				onff = newline_for_fun; | ||
|  | 				if (mandoc_command) { | ||
|  | 					scan_troff_mandoc(owndef->st + deflen + 2, 0, NULL); | ||
|  | 				} else { | ||
|  | 					scan_troff(owndef->st + deflen + 2, 0, NULL); | ||
|  | 				} | ||
|  | 				newline_for_fun = onff; | ||
|  | 				argument = oldargument; | ||
|  | 				for (i = 0; i < words; i++) | ||
|  | 					if (wordlist[i]) | ||
|  | 						free(wordlist[i]); | ||
|  | 				*sl = '\n'; | ||
|  | 			} else if (mandoc_command && | ||
|  | 				   ((isupper(*c) && islower(*(c + 1))) | ||
|  | 				    || (islower(*c) && isupper(*(c + 1)))) | ||
|  | 				) {	/* Let through any BSD mandoc
 | ||
|  | 					 * commands that haven't been delt | ||
|  | 					 * with. I don't want to miss | ||
|  | 					 * anything out of the text. */ | ||
|  | 				char    buf[4]; | ||
|  | 
 | ||
|  | 				strncpy(buf, c, 2); | ||
|  | 				buf[2] = ' '; | ||
|  | 				buf[3] = '\0'; | ||
|  | 				out_html(buf);	/* Print the command (it
 | ||
|  | 						 * might just be text). */ | ||
|  | 				c = c + j; | ||
|  | 				trans_char(c, '"', '\a'); | ||
|  | 				if (*c == '\n') | ||
|  | 					c++; | ||
|  | 				out_html(change_to_font('R')); | ||
|  | 				c = scan_troff(c, 1, NULL); | ||
|  | 				out_html(NEWLINE); | ||
|  | 				if (fillout) | ||
|  | 					curpos++; | ||
|  | 				else | ||
|  | 					curpos = 0; | ||
|  | 			} else { | ||
|  | 				c = skip_till_newline(c); | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if (fillout) { | ||
|  | 		out_html(NEWLINE); | ||
|  | 		curpos++; | ||
|  | 	} | ||
|  | 	NEWLINE[0] = '\n'; | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | static void | ||
|  | flush(void) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | static int contained_tab = 0; | ||
|  | static int mandoc_line = 0;	/* Signals whether to look for embedded
 | ||
|  | 				 * mandoc commands. */ | ||
|  | 
 | ||
|  | /* san : stop at newline */ | ||
|  | static char * | ||
|  | scan_troff(char *c, int san, char **result) | ||
|  | { | ||
|  | 	char   *h; | ||
|  | 	char    intbuff[NULL_TERMINATED(MED_STR_MAX)]; | ||
|  | 	int     ibp = 0; | ||
|  | 	int     i; | ||
|  | 	char   *exbuffer; | ||
|  | 	int     exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun; | ||
|  | 	int     usenbsp = 0; | ||
|  | 
 | ||
|  | #define FLUSHIBP  if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
 | ||
|  | 
 | ||
|  | 	exbuffer = buffer; | ||
|  | 	exbuffpos = buffpos; | ||
|  | 	exbuffmax = buffmax; | ||
|  | 	exnewline_for_fun = newline_for_fun; | ||
|  | 	exscaninbuff = scaninbuff; | ||
|  | 	newline_for_fun = 0; | ||
|  | 	if (result) { | ||
|  | 		if (*result) { | ||
|  | 			buffer = *result; | ||
|  | 			buffpos = strlen(buffer); | ||
|  | 			buffmax = buffpos; | ||
|  | 		} else { | ||
|  | 			buffer = stralloc(LARGE_STR_MAX); | ||
|  | 			buffpos = 0; | ||
|  | 			buffmax = LARGE_STR_MAX; | ||
|  | 		} | ||
|  | 		scaninbuff = 1; | ||
|  | 	} | ||
|  | 	h = c; | ||
|  | 	/* start scanning */ | ||
|  | 
 | ||
|  | 	while (*h && (!san || newline_for_fun || *h != '\n')) { | ||
|  | 
 | ||
|  | 		if (*h == escapesym) { | ||
|  | 			h++; | ||
|  | 			FLUSHIBP; | ||
|  | 			h = scan_escape(h); | ||
|  | 		} else if (*h == controlsym && h[-1] == '\n') { | ||
|  | 			h++; | ||
|  | 			FLUSHIBP; | ||
|  | 			h = scan_request(h); | ||
|  | 			if (san && h[-1] == '\n') | ||
|  | 				h--; | ||
|  | 		} else if (mandoc_line | ||
|  | 			   && *(h) && isupper(*(h)) | ||
|  | 			   && *(h + 1) && islower(*(h + 1)) | ||
|  | 			   && *(h + 2) && isspace(*(h + 2))) { | ||
|  | 			/*
 | ||
|  | 			 * BSD imbedded command eg ".It Fl Ar arg1 Fl Ar | ||
|  | 			 * arg2" | ||
|  | 			 */ | ||
|  | 			FLUSHIBP; | ||
|  | 			h = scan_request(h); | ||
|  | 			if (san && h[-1] == '\n') | ||
|  | 				h--; | ||
|  | 		} else if (*h == nobreaksym && h[-1] == '\n') { | ||
|  | 			h++; | ||
|  | 			FLUSHIBP; | ||
|  | 			h = scan_request(h); | ||
|  | 			if (san && h[-1] == '\n') | ||
|  | 				h--; | ||
|  | 		} else { | ||
|  | 			int     mx; | ||
|  | 
 | ||
|  | 			if (h[-1] == '\n' && still_dd && isalnum(*h)) { | ||
|  | 				/*
 | ||
|  | 				 * sometimes a .HP request is not followed by | ||
|  | 				 * a .br request | ||
|  | 				 */ | ||
|  | 				FLUSHIBP; | ||
|  | 				out_html("<DD>"); | ||
|  | 				curpos = 0; | ||
|  | 				still_dd = 0; | ||
|  | 			} | ||
|  | 			switch (*h) { | ||
|  | 			case '&': | ||
|  | 				intbuff[ibp++] = '&'; | ||
|  | 				intbuff[ibp++] = 'a'; | ||
|  | 				intbuff[ibp++] = 'm'; | ||
|  | 				intbuff[ibp++] = 'p'; | ||
|  | 				intbuff[ibp++] = ';'; | ||
|  | 				curpos++; | ||
|  | 				break; | ||
|  | 			case '<': | ||
|  | 				intbuff[ibp++] = '&'; | ||
|  | 				intbuff[ibp++] = 'l'; | ||
|  | 				intbuff[ibp++] = 't'; | ||
|  | 				intbuff[ibp++] = ';'; | ||
|  | 				curpos++; | ||
|  | 				break; | ||
|  | 			case '>': | ||
|  | 				intbuff[ibp++] = '&'; | ||
|  | 				intbuff[ibp++] = 'g'; | ||
|  | 				intbuff[ibp++] = 't'; | ||
|  | 				intbuff[ibp++] = ';'; | ||
|  | 				curpos++; | ||
|  | 				break; | ||
|  | 			case '"': | ||
|  | 				intbuff[ibp++] = '&'; | ||
|  | 				intbuff[ibp++] = 'q'; | ||
|  | 				intbuff[ibp++] = 'u'; | ||
|  | 				intbuff[ibp++] = 'o'; | ||
|  | 				intbuff[ibp++] = 't'; | ||
|  | 				intbuff[ibp++] = ';'; | ||
|  | 				curpos++; | ||
|  | 				break; | ||
|  | 			case '\n': | ||
|  | 				if (h[-1] == '\n' && fillout) { | ||
|  | 					intbuff[ibp++] = '<'; | ||
|  | 					intbuff[ibp++] = 'P'; | ||
|  | 					intbuff[ibp++] = '>'; | ||
|  | 				} | ||
|  | 				if (contained_tab && fillout) { | ||
|  | 					intbuff[ibp++] = '<'; | ||
|  | 					intbuff[ibp++] = 'B'; | ||
|  | 					intbuff[ibp++] = 'R'; | ||
|  | 					intbuff[ibp++] = '>'; | ||
|  | 				} | ||
|  | 				contained_tab = 0; | ||
|  | 				curpos = 0; | ||
|  | 				usenbsp = 0; | ||
|  | 				intbuff[ibp++] = '\n'; | ||
|  | 				break; | ||
|  | 			case '\t': | ||
|  | 				{ | ||
|  | 					int     curtab = 0; | ||
|  | 
 | ||
|  | 					contained_tab = 1; | ||
|  | 					FLUSHIBP; | ||
|  | 					/* like a typewriter, not like TeX */ | ||
|  | 					tabstops[19] = curpos + 1; | ||
|  | 					while (curtab < maxtstop && tabstops[curtab] <= curpos) | ||
|  | 						curtab++; | ||
|  | 					if (curtab < maxtstop) { | ||
|  | 						if (!fillout) { | ||
|  | 							while (curpos < tabstops[curtab]) { | ||
|  | 								intbuff[ibp++] = ' '; | ||
|  | 								if (ibp > 480) { | ||
|  | 									FLUSHIBP; | ||
|  | 								} | ||
|  | 								curpos++; | ||
|  | 							} | ||
|  | 						} else { | ||
|  | 							out_html("<TT>"); | ||
|  | 							while (curpos < tabstops[curtab]) { | ||
|  | 								out_html(" "); | ||
|  | 								curpos++; | ||
|  | 							} | ||
|  | 							out_html("</TT>"); | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				break; | ||
|  | 			default: | ||
|  | 				if (*h == ' ' && (h[-1] == '\n' || usenbsp)) { | ||
|  | 					FLUSHIBP; | ||
|  | 					if (!usenbsp && fillout) { | ||
|  | 						out_html("<BR>"); | ||
|  | 						curpos = 0; | ||
|  | 					} | ||
|  | 					usenbsp = fillout; | ||
|  | 					if (usenbsp) | ||
|  | 						out_html(" "); | ||
|  | 					else | ||
|  | 						intbuff[ibp++] = ' '; | ||
|  | 				} else if (*h > 31 && *h < 127) | ||
|  | 					intbuff[ibp++] = *h; | ||
|  | 				else if (((unsigned char) (*h)) > 127) { | ||
|  | 					intbuff[ibp++] = '&'; | ||
|  | 					intbuff[ibp++] = '#'; | ||
|  | 					intbuff[ibp++] = '0' + ((unsigned char) (*h)) / 100; | ||
|  | 					intbuff[ibp++] = '0' + (((unsigned char) (*h)) % 100) / 10; | ||
|  | 					intbuff[ibp++] = '0' + ((unsigned char) (*h)) % 10; | ||
|  | 					intbuff[ibp++] = ';'; | ||
|  | 				} | ||
|  | 				curpos++; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			if (ibp > (MED_STR_MAX - 20)) | ||
|  | 				FLUSHIBP; | ||
|  | 			h++; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	FLUSHIBP; | ||
|  | 	if (buffer) | ||
|  | 		buffer[buffpos] = '\0'; | ||
|  | 	if (san && *h) | ||
|  | 		h++; | ||
|  | 	newline_for_fun = exnewline_for_fun; | ||
|  | 	if (result) { | ||
|  | 		*result = buffer; | ||
|  | 		buffer = exbuffer; | ||
|  | 		buffpos = exbuffpos; | ||
|  | 		buffmax = exbuffmax; | ||
|  | 		scaninbuff = exscaninbuff; | ||
|  | 	} | ||
|  | 	return h; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static char * | ||
|  | scan_troff_mandoc(char *c, int san, char **result) | ||
|  | { | ||
|  | 	char   *ret, *end = c; | ||
|  | 	int     oldval = mandoc_line; | ||
|  | 
 | ||
|  | 	mandoc_line = 1; | ||
|  | 	while (*end && *end != '\n') { | ||
|  | 		end++; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (end > c + 2 | ||
|  | 	    && ispunct(*(end - 1)) | ||
|  | 	    && isspace(*(end - 2)) && *(end - 2) != '\n') { | ||
|  | 		/*
 | ||
|  | 		 * Don't format lonely punctuation E.g. in "xyz ," format the | ||
|  | 		 * xyz and then append the comma removing the space. | ||
|  | 		 */ | ||
|  | 		*(end - 2) = '\n'; | ||
|  | 		ret = scan_troff(c, san, result); | ||
|  | 		*(end - 2) = *(end - 1); | ||
|  | 		*(end - 1) = ' '; | ||
|  | 	} else { | ||
|  | 		ret = scan_troff(c, san, result); | ||
|  | 	} | ||
|  | 	mandoc_line = oldval; | ||
|  | 	return ret; | ||
|  | } | ||
|  | 
 | ||
|  | main(int argc, char **argv) | ||
|  | { | ||
|  | 	FILE   *f; | ||
|  | 	char   *t; | ||
|  | 	int     l, i; | ||
|  | 	char   *buf; | ||
|  | 	char   *h, *fullname; | ||
|  | 	STRDEF *stdf; | ||
|  | 
 | ||
|  | 	t = NULL; | ||
|  | 	while ((i = getopt(argc, argv, "")) != EOF) { | ||
|  | 		switch (i) { | ||
|  | 		default: | ||
|  | 			usage(); | ||
|  | 			exit(EXIT_USAGE); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (argc != 2) { | ||
|  | 		usage(); | ||
|  | 		exit(EXIT_USAGE); | ||
|  | 	} | ||
|  | 	h = t = argv[1]; | ||
|  | 	i = 0; | ||
|  | 
 | ||
|  | 	buf = read_man_page(h); | ||
|  | 	if (!buf) { | ||
|  | 		fprintf(stderr, "man2html: cannot read %s: %s\n", h, strerror(errno)); | ||
|  | 		exit(1); | ||
|  | 	} | ||
|  | #ifdef MAKEINDEX
 | ||
|  | 	idxfile = fopen(INDEXFILE, "a"); | ||
|  | #endif
 | ||
|  | 	stdf = &standardchar[0]; | ||
|  | 	i = 0; | ||
|  | 	while (stdf->nr) { | ||
|  | 		stdf->next = &standardchar[i]; | ||
|  | 		stdf = stdf->next; | ||
|  | 		i++; | ||
|  | 	} | ||
|  | 	chardef = &standardchar[0]; | ||
|  | 
 | ||
|  | 	stdf = &standardstring[0]; | ||
|  | 	i = 0; | ||
|  | 	while (stdf->nr) { | ||
|  | 		stdf->next = &standardstring[i]; | ||
|  | 		stdf = stdf->next; | ||
|  | 		i++; | ||
|  | 	} | ||
|  | 	strdef = &standardstring[0]; | ||
|  | 
 | ||
|  | 	intdef = &standardint[0]; | ||
|  | 	i = 0; | ||
|  | 	while (intdef->nr) { | ||
|  | 		intdef->next = &standardint[i]; | ||
|  | 		intdef = intdef->next; | ||
|  | 		i++; | ||
|  | 	} | ||
|  | 	intdef = &standardint[0]; | ||
|  | 
 | ||
|  | 	defdef = NULL; | ||
|  | 
 | ||
|  | 	scan_troff(buf + 1, 0, NULL); | ||
|  | 
 | ||
|  | 	while (itemdepth || dl_set[itemdepth]) { | ||
|  | 		out_html("</DL>\n"); | ||
|  | 		if (dl_set[itemdepth]) | ||
|  | 			dl_set[itemdepth] = 0; | ||
|  | 		else if (itemdepth > 0) | ||
|  | 			itemdepth--; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	out_html(change_to_font(0)); | ||
|  | 	out_html(change_to_size(0)); | ||
|  | 	if (!fillout) { | ||
|  | 		fillout = 1; | ||
|  | 		out_html("</PRE>"); | ||
|  | 	} | ||
|  | 	out_html(NEWLINE); | ||
|  | 
 | ||
|  | 	if (output_possible) { | ||
|  | 		/*   for mosaic users */ | ||
|  | 		fputs("<HR>\n<A NAME=\"index\"> </A><H2>Index</H2>\n<DL>\n", stdout); | ||
|  | 		manidx[mip] = 0; | ||
|  | 		fputs(manidx, stdout); | ||
|  | 		if (subs) | ||
|  | 			fputs("</DL>\n", stdout); | ||
|  | 		fputs("</DL>\n", stdout); | ||
|  | 		print_sig(); | ||
|  | 		fputs("</BODY>\n</HTML>\n", stdout); | ||
|  | 	} else | ||
|  | 		fprintf(stderr, "man2html: no output produced\n"); | ||
|  | #ifdef MAKEINDEX
 | ||
|  | 	if (idxfile) | ||
|  | 		fclose(idxfile); | ||
|  | #endif
 | ||
|  | 	exit(EXIT_SUCCESS); | ||
|  | } |