#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
#define MAX_ZCATS 10
#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)] = "";
static char th_page_and_sec[128] = { '\0' };
static char th_datestr[128] = { '\0' };
static char th_version[128] = { '\0' };
char *signature = "<HR>\nThis document was created by man2html from %s.<BR>\nTime: %s\n";
#define TIMEFORMAT "%d %B %Y %T %Z"
char *manpage;
#define BL_DESC_LIST 1
#define BL_BULLET_LIST 2
#define BL_ENUM_LIST 4
#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
{
sprintf(emsg, "Unknown system error %d", e);
return (&emsg[0]);
}
}
#endif
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)
{
char *new = malloc((len + 1) * sizeof(char));
if (!new) {
fprintf(stderr, "man2html: out of memory");
exit(EXIT_FAILURE);
}
return new;
}
static char *
strduplicate(char *from)
{
char *new = stralloc(strlen(from));
strcpy(new, from);
return new;
}
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;
}
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;
}
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");
}
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},
{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}
};
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 = localtime(&clock);
strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm);
printf(signature, manpage, 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] == '<') {
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;
static void
add_links(char *c)
{
int i, j, nr;
char *f, *g, *h;
char *idtest[6];
out_length += strlen(c);
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:
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:
#if 0
f = idtest[j];
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')))) {
h = f - 1;
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;
case 3:
case 2:
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:
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:
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] == ';') {
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;
}
c = scan_format(c, &layout, &maxcol);
currow = layout;
next_row(currow);
curfield = layout->first;
i = 0;
while (!finished) {
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])) {
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;
}
}
}
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;
}
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] == '(')) {
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)) {
switch (*c) {
case 'i':
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++;
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 *
unescape (char *c)
{
int i, l;
l = strlen (c);
i = 0;
while (i < l && c[i]) {
if (c[i] == '\a') {
if (c[i+1])
memmove(c + i, c + i + 1, strlen(c + i + 1) + 1);
else {
c[i] = '\0';
break;
}
}
i++;
}
return c;
}
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 == '\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 void
outputPageHeader(char *l, char *c, char *r)
{
out_html("<TABLE WIDTH=100%>\n<TR>\n");
out_html("<TH ALIGN=LEFT width=33%>");
out_html(l);
out_html("<TH ALIGN=CENTER width=33%>");
out_html(c);
out_html("<TH ALIGN=RIGHT width=33%>");
out_html(r);
out_html("\n</TR>\n</TABLE>\n");
}
static void
outputPageFooter(char *l, char *c, char *r)
{
out_html("<HR>\n");
outputPageHeader(l, c, r);
}
static int ifelseval = 0;
static char *
scan_request(char *c)
{
static int mandoc_synopsis = 0;
static int mandoc_command = 0;
static int mandoc_bd_options;
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) {
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);
}
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);
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'):
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'):
case V('i', 'f'):
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
{
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'):
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';
*c = '\n';
break;
case V('B', ' '):
case V('B', '\n'):
case V('I', ' '):
case V('I', '\n'):
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'):
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;
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);
if (!*c)
still_dd = 1;
else {
c = scan_troff(c, 1, NULL);
out_html("<DD>");
}
curpos = 0;
break;
case V('I', 'X'):
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);
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'):
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'):
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'):
mandoc_command = 1;
case V('S', 'S'):
mode = 1;
case V('S', 'h'):
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);
if (mode)
out_html("\"> </A>\n<H4>");
else
out_html("\"> </A>\n<H3>");
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("</H4>\n");
else
out_html("</H3>\n");
curpos = 0;
break;
case V('T', 'S'):
c = scan_table(c);
break;
case V('D', 't'):
mandoc_command = 1;
case V('T', 'H'):
if (!output_possible) {
sl = fill_words(c + j, wordlist, &words);
if (words > 1) {
char *t;
for (i = 1; i < words; i++)
wordlist[i][-1] = '\0';
*sl = '\0';
output_possible = 1;
sprintf(th_page_and_sec, "%s(%s)", wordlist[0], wordlist[1]);
if (words > 2) {
t = unescape(wordlist[2]);
strncpy(th_datestr, t, sizeof(th_datestr));
th_datestr[sizeof(th_datestr) - 1] = '\0';
} else
th_datestr[0] = '\0';
if (words > 3) {
t = unescape(wordlist[3]);
strncpy(th_version, t, sizeof(th_version));
th_version[sizeof(th_version) - 1] = '\0';
} else
th_version[0] = '\0';
out_html("<HTML><HEAD>\n<TITLE>");
out_html(th_page_and_sec);
out_html(" Manual Page");
out_html("</TITLE>\n</HEAD>\n<BODY>");
outputPageHeader(th_page_and_sec, th_datestr, th_page_and_sec);
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'):
case V('r', 'n'):
{
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'):
case V('i', 'n'):
c = skip_till_newline(c);
break;
case V('n', 'r'):
{
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'):
mode = 1;
case V('d', 'e'):
{
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'):
{
char list_options[NULL_TERMINATED(MED_STR_MAX)];
char *nl = strchr(c, '\n');
c = c + j;
if (dl_set[itemdepth]) {
itemdepth++;
}
if (nl) {
strlimitcpy(list_options, c, nl - c, MED_STR_MAX);
}
if (strstr(list_options, "-bullet")) {
dl_set[itemdepth] = BL_BULLET_LIST;
out_html("<UL>\n");
} else if (strstr(list_options, "-enum")) {
dl_set[itemdepth] = BL_ENUM_LIST;
out_html("<OL>\n");
} else {
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'):
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'):
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') {
c++;
c = scan_troff(c, 1, NULL);
} else {
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'):
case V('E', 'k'):
case V('D', 'd'):
case V('O', 's'):
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'):
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'):
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'):
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'):
{
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;
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'):
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'):
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'):
{
char buff[NULL_TERMINATED(MED_STR_MAX)];
char *bufptr;
trans_char(c, '"', '\a');
bufptr = buff;
c = c + j;
if (*c == '\n')
c++;
while (isspace(*c) && *c != '\n')
c++;
while (isalnum(*c)) {
*bufptr = *c;
bufptr++;
if (bufptr >= buff + MED_STR_MAX)
break;
c++;
}
while (isspace(*c) && *c != '\n')
c++;
if (isdigit(*c)) {
*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') {
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'):
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'):
case V('P', 'f'):
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'):
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'):
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'):
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'):
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'):
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'):
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'):
{
char *sp;
trans_char(c, '"', '\a');
c = c + j;
if (*c == '\n')
c++;
sp = c;
do {
while (*sp && isspace(*sp))
sp++;
while (*sp && !isspace(*sp))
sp++;
} while (*sp && isupper(*(sp - 2)) && islower(*(sp - 1)));
if (*sp)
*sp = '\n';
out_html("`");
c = scan_troff_mandoc(c, 1, NULL);
out_html("'");
out_html(NEWLINE);
if (fillout)
curpos++;
else
curpos = 0;
break;
}
case V('S', 'q'):
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'):
out_html(change_to_font('I'));
trans_char(c, '"', '\a');
c = c + j;
if (*c == '\n') {
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'):
case V('E', 'm'):
case V('V', 'a'):
case V('X', 'c'):
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'):
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'):
{
static char mandoc_name[NULL_TERMINATED(SMALL_STR_MAX)] = "";
trans_char(c, '"', '\a');
c = c + j;
if (mandoc_synopsis) {
static int count = 0;
if (count) {
out_html("<BR>");
} else {
char *end = strchr(c, '\n');
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') {
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'):
case V('C', 'm'):
case V('I', 'c'):
case V('M', 's'):
case V('O', 'r'):
case V('S', 'y'):
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'):
case V('E', 'v'):
case V('F', 'r'):
case V('L', 'i'):
case V('N', 'o'):
case V('N', 's'):
case V('T', 'n'):
case V('n', 'N'):
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'):
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);
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);
out_html(change_to_font('R'));
if (fillout)
curpos++;
else
curpos = 0;
break;
default:
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))))
) {
char buf[4];
strncpy(buf, c, 2);
buf[2] = ' ';
buf[3] = '\0';
out_html(buf);
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;
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;
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))) {
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)) {
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;
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') {
*(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);
}
manpage = 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) {
outputPageFooter(th_version, th_datestr, th_page_and_sec);
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);
}