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