/* ** 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. * In addition, * * Copyright (C) 1999 Red Hat Software * Changes licensed under the GNU Public License. */ /* * gnome-man2html2 * This version modified for GNOME - December 1999 * Elliot Lee * May this code live forever :) */ /* * gnome-man2html * This version modified for GNOME - February 1998 * Michael Fulbright */ /* * man2html-linux-1.0/1.1 * This version modified for Redhat/Caldera linux - March 1996. * Michael Hamilton . * * man2html-linux-1.2 * Added support for BSD mandoc pages - I didn't have any documentation * on the mandoc macros, so I may have missed some. * Michael Hamilton . * * vh-man2html-1.3 * Renamed to avoid confusion (V for Verhoeven, H for Hamilton). * * vh-man2html-1.4 * Now uses /etc/man.config * Added support for compressed pages. * Added "length-safe" string operations for client input parameters. * More secure, -M secured, and client input string lengths checked. * */ /* ** If you want to use this program for your WWW server, adjust the line ** which defines the CGIBASE or compile it with the -DCGIBASE='"..."' option. ** ** You have to adjust the built-in manpath to your local system. Note that ** every directory should start and end with the '/' and that the first ** directory should be "/" to allow a full path as an argument. ** ** The program first check if PATH_INFO contains some information. ** If it does (t.i. man2html/some/thing is used), the program will look ** for a manpage called PATH_INFO in the manpath. ** ** Otherwise the manpath is searched for the specified command line argument, ** where the following options can be used: ** ** name name of manpage (csh, printf, xv, troff) ** section the section (1 2 3 4 5 6 7 8 9 n l 1v ...) ** -M path an extra directory to look for manpages (replaces "/") ** ** If man2html finds multiple manpages that satisfy the options, an index ** is displayed and the user can make a choice. If only one page is ** found, that page will be displayed. ** ** 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 ** ^^^^ ** 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
)
**  * 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.)
*/


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#ifdef HAVE_LIBBZ2
#include 
#endif

static char *URLbasename = NULL;

#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 NROFF
#define NROFF 1
#endif

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

/* Don't bother with free(), it will just slow us down, the ultimate
   free will be exit() anyway.  Hack to fix a malloc bug that I couldn't
   track down (michael@actrix.gen.nz).
   */
#define free(x)

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;
}

static char
*strmaxcpy(char *to, char *from, int n)
{				/* Assumes space for n plus a null */
	int len = strlen(from);
	strncpy(to, from, n);
	to[(len <= n) ? len : n] = '\0';
	return to;
}

static char 
*strlimitcpy(char *to, char *from, int n, int limit)
{                               /* Assumes space for limit plus a null */
	int len = n > limit ? limit : n;
	strmaxcpy(to, from, len);
	to[len] = '\0';
	return to;
}

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

#ifdef MAXINDEX
static FILE *idxfile;
#endif

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, "{", 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, "}", 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 escapesym='\\', nobreaksym='\'', controlsym='.', fieldsym=0, padsym=0;

static gzFile infh = NULL;
#ifdef HAVE_LIBBZ2
static BZFILE * inbfh = NULL;
#endif
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 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;
}

/* msf - this will become real simple, as we read from stdin all the time */
/*       and it is always uncompressed                                    */
static char
*read_man_page(void) 
{
	char *man_buf = NULL;
	char buf[8192];
	int buf_size = 0;
	int bytes;

	/* input from stdin */
#ifdef HAVE_LIBBZ2
	if (inbfh) 
	  bytes = bzread(inbfh, buf, sizeof(buf));
	else
#endif
	  bytes = gzread(infh, buf, sizeof(buf));
	while (bytes > 0) {
		if (!man_buf) {
			man_buf = malloc(bytes+1);
			man_buf[0] = '\n';
			buf_size = 1;
		} else {
			man_buf = realloc(man_buf, bytes+buf_size);
		}

		memcpy(man_buf+buf_size, buf, bytes);
		buf_size += bytes;
#ifdef HAVE_LIBBZ2
		if (inbfh) 
		  bytes = bzread(inbfh, buf, sizeof(buf));
		else
#endif
		bytes = gzread(infh, buf, sizeof(buf));
	}

	if (man_buf) {
			man_buf = realloc(man_buf, buf_size+2);
			man_buf[buf_size]   = '\n';
			man_buf[buf_size+1] = '\0';
	}

	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:
**
** name(*)                 -> ../man?/name.*
** method://string         -> method://string
** www.host.name           -> http://www.host.name
** ftp.host.name           -> ftp://ftp.host.name
** name@host               -> mailto:name@host
**                 -> 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.");
	idtest[4]=strchr(c+1,'(');
	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] */
			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("%s>", g,g);
				c=f+6;
			} else {
				f[5]='\0';
				fputs(c, stdout);
				f[5]=';';
				c=f+5;
			}
			break;
		case 4: /* manpage */
			f=idtest[j];
			/* check section */
			g=strchr(f,')');
			if (g && f-g<6 && (isalnum((unsigned char)f[-1]) || f[-1]=='>') &&
			    ((isdigit((unsigned char)f[1]) && f[1]!='0' &&
			      (f[2]==')' || (isalpha((unsigned char)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((unsigned char)*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((unsigned char)h[-1]) ||
						       h[-1]=='_' ||
						       h[-1]=='-' || 
						       h[-1]=='.'))
						h--;
					t=*h;
					*h='\0';
					fputs(c, stdout);
					*h=t;
					t=*e;
					*e='\0';
/* old code using file: */
#if 0
					if (subsec)
						/* change to whatever you're using */
						printf("%s", 
						       sec, h, sec, tolower(subsec), h);
					else
						printf("%s", 
						       sec, h, sec, h);
#else
					/* The code used to take
					   'subsec' into account, but
					   (a) 'subsec' can be more than
					   one character (b) We have
					   no use for that information */

					printf("%s",
					       h, sec,
					       h);
#endif
					*e=t;
					c=e;
				}
			}
			*f='\0';
			fputs(c, stdout);
			*f='(';
			idtest[4]=f-1;
			c=f;
			break; /* manpage */
		case 3: /* ftp */
		case 2: /* www */
			g=f=idtest[j];
			while (*g && (isalnum((unsigned char)*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("%s", 
				       (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((unsigned char)g[-1]) || g[-1]=='_' 
				       || g[-1]=='-' ||
				       g[-1]=='+' || g[-1]=='.' 
				       || g[-1]=='%')) g--;
			h=f+1;
			while (*h && (isalnum((unsigned char)*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("%s",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((unsigned char)g[-1]) && islower((unsigned char)g[-1])) g--;
			h=f+3;
			while (*h && !isspace((unsigned char)*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("%s", 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]=buffmax) {
				char *h;
				h=realloc(buffer, buffmax*2);
				if (!h) return;
				buffer=h;
				buffmax=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 ""
#define FC1 ""
#define FO2 ""
#define FC2 ""
#define FO3 ""
#define FC3 ""

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, "");
	current_size=nr;
	if (nr) {
		int l;
		strcat(sizebuf, "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="
"; 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="
\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((unsigned char)*c) && *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((unsigned char)*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((unsigned char)*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 *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; 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("
"); } while (*h && *h!='\n') h++; if (h[-1]==';') { /* scan table options */ while (cfirst; 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((unsigned char)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->rowspanrowspan) 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("
"); if (box==2) out_html(""); curfield=currow->first; while (curfield) { if (curfield->align!='S' && curfield->align!='^') { out_html("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("

"); break; case '_': out_html("
"); break; default: if (curfield->contents) out_html(curfield->contents); break; } if (curfield->space) for (i=0; ispace;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("
"); out_html(""); } curfield=curfield->next; } out_html("
\n"); currow=currow->next; } if (box && !border) out_html("
"); out_html("
\n"); currow=layout; while (currow) { j=0; out_html("
"); out_html(""); if (box==2) out_html(""); if (center) out_html("
\n"); else out_html("\n"); if (!oldfillout) out_html("
");
	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,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((unsigned char)*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((unsigned char)*c))
					value2=value2*10+((*c++)-'0');
				if (*c=='.') {
					c++;
					while (isdigit((unsigned char)*c)) {
						num=num*10+((*c++)-'0');
						denum=denum*10;
					}
				}
				if (isalpha((unsigned char)*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((unsigned char)*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':
					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 nroff and troff",
    "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", "SPARC 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 *section_list[] = {
    "1", "User Commands ",
    "1C", "User Commands",
    "1G", "User Commands",
    "1S", "User Commands",
    "1V", "User Commands ",
    "2", "System Calls",
    "2V", "System Calls",
    "3", "C Library Functions",
    "3C", "Compatibility Functions",
    "3F", "Fortran Library Routines",
    "3K", "Kernel VM Library Functions",
    "3L", "Lightweight Processes Library",
    "3M", "Mathematical Library",
    "3N", "Network Functions",
    "3R", "RPC Services Library",
    "3S", "Standard I/O Functions",
    "3V", "C Library Functions",
    "3X", "Miscellaneous Library Functions",
    "4", "Devices and Network Interfaces",
    "4F", "Protocol Families",
    "4I", "Devices and Network Interfaces",
    "4M", "Devices and Network Interfaces",
    "4N", "Devices and Network Interfaces",
    "4P", "Protocols",
    "4S", "Devices and Network Interfaces",
    "4V", "Devices and Network Interfaces",
    "5", "File Formats",
    "5V", "File Formats",
    "6", "Games and Demos",
    "7", "Environments, Tables, and Troff Macros",
    "7V", "Environments, Tables, and Troff Macros",
    "8", "Maintenance Commands",
    "8C", "Maintenance Commands",
    "8S", "Maintenance Commands",
    "8V", "Maintenance Commands",
    "L", "Local Commands",
    NULL, "Misc. Reference Manual Pages",
    NULL, NULL
};

static char
*section_name(char *c)
{
    int i=0;

    if (!c)
	    return "";
    while (section_list[i] && strcmp(c,section_list[i]))
	    i=i+2;
    if (section_list[i+1])
	    return section_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, "\n", HUGE_STR_MAX - mip);
			mip+=6;
		} else {
			strmaxcpy(manidx+mip, "
\n", HUGE_STR_MAX - mip); mip+=5; } } subs=level; scan_troff(item, 1, &c); sprintf(manidx+mip, "
%s
\n", ((URLbasename) ? URLbasename : ""), 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 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('`',' '): out_html(change_to_font('B')); out_html("`"); trans_char(c,'"','\a'); c=c+j; if (*c!='\n') c++; c=scan_troff(c, 1, NULL); out_html("'"); out_html(change_to_font('R')); out_html(NEWLINE); if (fillout) curpos++; else curpos=0; break; 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; 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((unsigned char)*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("
"); else out_html("
\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("
\n"); while (i && *c) { char *line=NULL; c=scan_troff(c,1, &line); if (line && strncmp(line, "
", 4)) { out_html(line); out_html("
\n"); i--; } } out_html("
\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("
\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' && strncmp(c, "\\\"", 2)) { endwith=c-1;i=1; c[-1]='.'; while (*c && *c!='\n') { c++; i++; } } c++; while (*c && strncmp(c,endwith,i)) while (*c && *c++!='\n'); while (*c && *c++!='\n'); break; } case V('n','f'): if (fillout) { out_html(change_to_font(0)); out_html(change_to_size('0')); out_html("
\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("

"); else { out_html(NEWLINE); NEWLINE[0]='\n'; } curpos=0; c=skip_till_newline(c); break; case V('s','o'): { /* msf */ 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'; *c++='\n'; printf(" WARNING - a .so macro slipped " "through!\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("\n"); if (dl_set[itemdepth]) dl_set[itemdepth]=0; else itemdepth--; }*/ out_html("
\n"); c=c+j; c=scan_expression(c, &j); for (i=0; ia b ] */ 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\n"); dl_set[itemdepth]=1; } out_html("

"); if (words) { scan_troff(wordlist[0], 1,NULL); } out_html("
"); curpos=0; break; case V('T','P'): if (!dl_set[itemdepth]) { out_html("
\n"); dl_set[itemdepth]=1; } out_html("
"); 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("
"); } 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' and '<' solves it, ** but creates ** some space. A normal space does not work. */ out_html("\">"); break; case V('L','P'): case V('P','P'): if (dl_set[itemdepth]) { out_html("
\n"); dl_set[itemdepth]=0; } if (fillout) out_html("

\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_set[itemdepth]=1; } out_html("
\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("
"); 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("
"); out_html("
\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("\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("
"); } trans_char(c,'"', '\a'); add_to_index(mode, c); out_html(" \n

"); else out_html("\"> \n

"); 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("

\n"); else out_html("\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) { for (i=1; i" "Manpage of "); out_html(wordlist[0]); out_html("\n" "\n

"); out_html(wordlist[0]); out_html("

\nSection: "); if (words>4) out_html(wordlist[4]); else out_html(section_name( wordlist[1])); out_html(" ("); out_html(wordlist[1]); if (words>2) { out_html(")
Updated: "); scan_troff(wordlist[2], 1, NULL); } else out_html(")"); out_html("\n"); printf("
Index\n"); #if 0 out_html("
Index\n"); #endif *sl='\n'; #if 0 fputs("
Return to Main Contents\n", stdout); #endif out_html("
\n"); if (mandoc_command) out_html("
BSD mandoc
"); } 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((unsigned char)*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; jst[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("
    \n"); } else if (strstr(list_options, "-enum")) { /* HTML Ordered List */ dl_set[itemdepth] = BL_ENUM_LIST; out_html("
      \n"); } else { /* HTML Descriptive List */ dl_set[itemdepth] = BL_DESC_LIST; out_html("
      \n"); } if (fillout) out_html("

      \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("

      \n"); } else if (dl_set[itemdepth] & BL_BULLET_LIST) { out_html("
\n"); } else if (dl_set[itemdepth] & BL_ENUM_LIST) { out_html("\n"); } dl_set[itemdepth]=0; if (itemdepth > 0) itemdepth--; if (fillout) out_html("

\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((unsigned char)*(c+2))) { c = skip_till_newline(c); } if (dl_set[itemdepth] & BL_DESC_LIST) { out_html("

"); 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("
"); } else if (dl_set[itemdepth] & (BL_BULLET_LIST | BL_ENUM_LIST)) { out_html("
  • "); 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("
    "); 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("
    "); 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); /* Remember options for terminating Bl */ mandoc_bd_options = 0; if (strstr(bd_options, "-offset indent")) { mandoc_bd_options |= BD_INDENT; out_html("
    \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("
    \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("
    \n"); } } if (mandoc_bd_options & BD_INDENT) out_html("
    \n"); curpos=0; fillout=1; c=skip_till_newline(c); break; case V('B','e'): /* BSD mandoc */ c=c+j; if (fillout) out_html("

    "); 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((unsigned char)*c) && *c != '\n') c++; while (isalnum((unsigned char)*c)) { /* Copy the xyz part */ *bufptr = *c; bufptr++; if (bufptr >= buff + MED_STR_MAX) break; c++; } while (isspace((unsigned char)*c) && *c != '\n') c++; /* Skip spaces */ /* Convert the number if there is one */ if (isdigit((unsigned char)*c)) { *bufptr = '('; bufptr++; if (bufptr < buff + MED_STR_MAX) { while (isalnum((unsigned char)*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((unsigned char)*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("

    \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((unsigned char)*sp)) sp++; while (*sp && !isspace((unsigned char)*sp)) sp++; } while (*sp && isupper((unsigned char)*(sp-2)) && islower((unsigned char)*(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("
    "); } else { char *end = strchr(c, '\n'); /* Remember the name for later. */ if (end) { 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++; /* Don't allow embedded mandoc coms */ c=scan_troff(c, 1, NULL); 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++; /* Don't allow embedded mandoc coms */ c=scan_troff(c, 1, NULL); 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;ist); 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"); 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 (curtab480) { FLUSHIBP; } curpos++; } } else { out_html(""); while (curpos"); } } } break; default: if (*h==' ' && (h[-1]=='\n' || usenbsp)) { FLUSHIBP; if (!usenbsp && fillout) { out_html("
    "); 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((unsigned char)*(end - 1)) && isspace((unsigned char)*(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; } int main(int argc, char **argv) { char *t=NULL; int i; char *buf; char *h = '\0'; STRDEF *stdf; char *infile = NULL; /* see if they gave us a basename for the URL references */ for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-n")) { i++; if(i >= argc) return 1; URLbasename = strdup(argv[i]); } else if(argv[i][0] == '-') return 2; else infile = argv[i]; } if(!infile || !strcmp(infile, "-")) infh = gzdopen(0, "r"); else { #ifdef HAVE_LIBBZ2 if (strstr(infile,".bz2")) inbfh = bzopen(infile, "r"); else #endif infh = gzopen(infile, "r"); #ifdef HAVE_LIBBZ2 if(!infh && !inbfh) #else if(!infh) #endif { FILE *fh; char cmdline[512], *ctmp, output[512]; /* Try searching for this as a man page name, instead */ ctmp = strrchr(infile, '.'); if(ctmp && (isdigit((unsigned char)*(ctmp+1)) || (*(ctmp+1) == 'n')) && *(ctmp+2) == '\0') { char section = *(ctmp+1); *ctmp = '\0'; snprintf(cmdline, sizeof(cmdline), "man -w %c %s", section, infile); } else snprintf(cmdline, sizeof(cmdline), "man -w %s", infile); fh = popen(cmdline, "r"); fgets(output, sizeof(output), fh); pclose(fh); i = strlen(output) - 1; while(isspace((unsigned char)output[i])) output[i--] = '\0'; if (output[0]) { #ifdef HAVE_LIBBZ2 if(strstr(output,".bz2")) inbfh = bzopen(output, "r"); else #endif infh = gzopen(output, "r"); } } } #ifdef HAVE_LIBBZ2 if(!infh && !inbfh) #else if(!infh) #endif { printf("Document not found\n" "The document \"%s\" couldn't be found. It may have been removed from your system.\n" "\n", infile); return 3; } buf=read_man_page(); if (!buf) { t=strrchr(h,'.'); if (t) *t='\0'; t=strrchr(h,'/'); if (!t) t=h; else t++; printf("Bad manpage.\n" "\n

    Bad manpage.

    \n" "Sorry, unable to convert the manpage.\n" "\n"); exit(0); } fname=h; 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("\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(""); } out_html(NEWLINE); if (output_possible) { /*   for mosaic users */ fputs("
    \n 

    Index

    \n
    \n", stdout); manidx[mip]=0; fputs(manidx,stdout); if (subs) fputs("
    \n", stdout); fputs("\n", stdout); /* print_sig(); */ fputs("\n\n", stdout); } else { printf("Invalid Manpage\n" "

    Invalid Manpage

    \n" "You tried to retrieve an incorrect manpage.\n" "The page does not contain a manpage header and will\n" "not produce any output.\n" "If the page is a formatted manpage, you might want to use\n" "a different man2html (or cat2html) converter.\n"); /* print_sig(); */ fputs("\n\n", stdout); } if (buf) free(buf); return 0; }