summaryrefslogtreecommitdiffstats
path: root/man2html/man2html.c
diff options
context:
space:
mode:
Diffstat (limited to 'man2html/man2html.c')
-rw-r--r--man2html/man2html.c3241
1 files changed, 3241 insertions, 0 deletions
diff --git a/man2html/man2html.c b/man2html/man2html.c
new file mode 100644
index 0000000..b37eef6
--- /dev/null
+++ b/man2html/man2html.c
@@ -0,0 +1,3241 @@
+/*
+** 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.
+*/
+
+/* BSD mandoc stuff added by Michael Hamilton. */
+
+/* This program is rather buggy, but in spite of that it often works.
+ Improved things a little - April 1997 & January 1998 & Dec 2001 -
+ aeb@cwi.nl. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include "defs.h"
+#include "../src/version.h"
+
+/* BSD mandoc Bd/Ed example(?) blocks */
+#define BD_LITERAL 1
+#define BD_INDENT 2
+
+#define SIZE(a) (sizeof(a)/sizeof(*a))
+
+static char NEWLINE[2]="\n";
+static char idxlabel[6] = "ixAAA";
+
+#define INDEXFILE "/tmp/manindex.list"
+
+char *fname;
+char *directory;
+FILE *idxfile;
+
+char eqndelimopen=0, eqndelimclose=0;
+char escapesym='\\', nobreaksym='\'', controlsym='.', fieldsym=0, padsym=0;
+
+char *buffer=NULL;
+int buffpos=0, buffmax=0;
+int scaninbuff=0;
+int still_dd=0;
+int tabstops[20] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
+int maxtstop=12;
+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[3];
+
+static char *
+expand_char(int nr)
+{
+ STRDEF *h;
+
+ if (!nr)
+ return NULL;
+
+ h = chardef;
+ if (h->nr != V('*','*')) {
+ printf("chardef corrupted\n");
+ exit(1);
+ }
+
+ for (h = chardef; h; h = h->next)
+ if (h->nr == nr) {
+ curpos += h->slen;
+ return h->st;
+ }
+ charb[0] = nr/256;
+ charb[1] = nr%256;
+ charb[2] = 0;
+ curpos += 2;
+ return charb;
+}
+
+static char *
+expand_string(int nr)
+{
+ STRDEF *h;
+
+ if (!nr)
+ return NULL;
+ for (h = strdef; h; h = h->next)
+ if (h->nr == nr) {
+ curpos += h->slen;
+ return h->st;
+ }
+ return NULL;
+}
+
+
+static char outbuffer[1024];
+static int obp=0;
+static int no_newline_output=0; /* boolean, set by \c */
+static int newline_for_fun=0;
+static int output_possible=0;
+static int out_length=0;
+
+static void
+add_links(char *c)
+{
+ /*
+ ** Add the links to the output.
+ ** At the moment the following are recognized:
+ **
+ ** name(*) -> ../man?/name.*
+ ** method://string -> method://string
+ ** www.host.name -> http://www.host.name
+ ** ftp.host.name -> ftp://ftp.host.name
+ ** name@host -> mailto:name@host
+ ** <name.h> -> file:/usr/include/name.h (guess)
+ **
+ ** Other possible links to add in the future:
+ **
+ ** /dir/dir/file -> file:/dir/dir/file
+ */
+ int i,j,nr;
+ char *f, *g, *h;
+ char *idtest[6]; /* url, mailto, www, ftp, manpage, include file */
+
+ 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.");
+ idtest[4]=strchr(c+1,'(');
+ idtest[5]=strstr(c+1,".h&gt;");
+ 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;
+ printf("%s",c);
+ *g=t;*h=0;
+ include_file_html(g);
+ c=f+6;
+ } else {
+ f[5]=0;
+ printf("%s",c);
+ f[5]=';';
+ c=f+5;
+ }
+ break;
+ case 4: /* manpage? */
+ f=idtest[j];
+ /* find section - accept (1), (3F), (3Xt), (n), (l) */
+ g=strchr(f,')');
+ if (g && g-f<7 /* section has length at most 5, like 3Xlib */
+ /* preceded by name or html markup */
+ && (isalnum(f[-1]) || f[-1]=='>')
+ /* section is n or l or starts with a digit */
+ && strchr("123456789nl", f[1])
+ && (g-f == 2 || (g-f == 3 && isdigit(f[1]) && isalpha(f[2]))
+ || (f[2] == 'X' && isdigit(f[1])))
+ ) {
+ /* this might be a link */
+ h=f-1;
+ /* skip html markup */
+ while (h>c && *h=='>') {
+ while (h!=c && *h!='<') h--;
+ if (h!=c) h--;
+ }
+ if (isalnum(*h)) {
+ char t,te,tg,*e;
+ e=h+1;
+ while (h>c && (isalnum(h[-1]) || h[-1]=='_' ||
+ h[-1]=='-' || h[-1]=='.' || h[-1]==':'))
+ h--;
+ t=*h; *h=0;
+ printf("%s", c);
+ *h=t;
+ tg=*g; *g=0;
+ te=*e; *e=0;
+ man_page_html(f+1, h); /* section, page */
+ *e=te;
+ *g=tg;
+ c=e;
+ }
+ }
+ *f=0;
+ printf("%s", c);
+ *f='(';
+ idtest[4]=f-1;
+ c=f;
+ 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;
+ printf("%s",c);
+ *f=t; t=*g;*g=0;
+ if (j==3)
+ ftp_html(f);
+ else
+ www_html(f);
+ *g=t;
+ c=g;
+ } else {
+ f[3]=0;
+ printf("%s",c);
+ 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[-1]=='.') h--;
+ if (h-f>4 && f-g>1) {
+ char t;
+ t=*g;
+ *g=0;
+ printf("%s",c);
+ *g=t;t=*h;*h=0;
+ mailto_html(g);
+ *h=t;
+ c=h;
+ } else {
+ *f=0;
+ printf("%s",c);
+ *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;
+ printf("%s", c);
+ *g=t; t=*h; *h=0;
+ url_html(g);
+ *h=t;
+ c=h;
+ } else {
+ f[1]=0;
+ printf("%s", c);
+ 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&gt;");
+ for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
+ }
+ printf("%s", c);
+}
+
+int current_font=0;
+int current_size=0;
+int fillout = 1;
+
+/*
+ * Kludge: remove \a - in the context
+ * .TH NAME 2 date "Version" "Title"
+ * we got output \aTitle\a.
+ */
+static void
+out_html(char *c) {
+ if (!c)
+ return;
+ if (no_newline_output) { /* remove \n if present */
+ int i=0;
+ while (c[i]) {
+ if (!no_newline_output)
+ c[i-1]=c[i];
+ if (c[i]=='\n')
+ no_newline_output=0;
+ i++;
+ }
+ if (!no_newline_output)
+ c[i-1]=0;
+ }
+ if (scaninbuff) {
+ while (*c) {
+ if (buffpos >= buffmax) {
+ buffer = xrealloc(buffer, buffmax*2);
+ buffmax = buffmax*2;
+ }
+ if (*c != '\a')
+ buffer[buffpos++] = *c;
+ c++;
+ }
+ } else if (output_possible) {
+ while (*c) {
+ if (*c != '\a')
+ outbuffer[obp++] = *c;
+ if (*c == '\n' || obp > 1000) {
+ outbuffer[obp] = 0;
+ add_links(outbuffer);
+ obp = 0;
+ }
+ c++;
+ }
+ }
+}
+
+/* --------------------------------------------------------------- */
+/* All references to dl_set and itemdepth are here. */
+/* --------------------------------------------------------------- */
+static int itemdepth=0;
+static int dl_set[30]= { 0 };
+#define noDL 0
+#define DL 1
+#define UL 2
+#define OL 3
+static char *dl_open[4] = { "", "<DL COMPACT>\n", "<UL>", "<OL>" };
+static char *dl_close[4] = { "", "</DL>\n", "</UL>", "</OL>" };
+
+static inline void
+dl_begin(void) {
+ if (itemdepth < SIZE(dl_set) && dl_set[itemdepth] == noDL) {
+ out_html(dl_open[DL]);
+ dl_set[itemdepth]=DL;
+ }
+ out_html("<DT>");
+}
+
+static inline void
+dl_end(void) {
+ if (itemdepth < SIZE(dl_set)) {
+ int type = dl_set[itemdepth];
+ if (type == DL) {
+ out_html(dl_close[type]);
+ dl_set[itemdepth]=noDL;
+ }
+ }
+}
+
+static inline void
+dl_newlevel(void) {
+ itemdepth++;
+ if (itemdepth < SIZE(dl_set))
+ dl_set[itemdepth]=noDL;
+ out_html("<DL COMPACT><DT><DD>");
+}
+
+static inline void
+dl_endlevel(void) {
+ if (itemdepth) {
+ dl_end();
+ out_html("</DL>\n");
+ itemdepth--;
+ }
+}
+
+static inline void
+dl_down(void) {
+ while (itemdepth)
+ dl_endlevel();
+ dl_end();
+}
+
+static inline int
+dl_type(int type) {
+ return (itemdepth < SIZE(dl_set) && dl_set[itemdepth] == type);
+}
+
+static inline void
+dl_newlevel_type(int type) {
+ itemdepth++;
+ if (itemdepth < SIZE(dl_set)) {
+ dl_set[itemdepth]=type;
+ out_html(dl_open[type]);
+ }
+}
+
+static inline void
+dl_endlevel_type(void) {
+ if (itemdepth) {
+ if (itemdepth < SIZE(dl_set))
+ out_html(dl_close[dl_set[itemdepth]]);
+ itemdepth--;
+ }
+}
+/* --------------------------------------------------------------- */
+/* This stuff is broken.
+It generates
+ <DT><B>TIOCLINUX, subcode=0<DD>
+ Dump the screen.
+ </B><I>argp</I> points to a
+from
+ .IP "\fBTIOCLINUX, subcode=0"
+ Dump the screen.
+ \fIargp\fP points to a
+Bug 1: incorrect nesting: </B> is needed before <DD>.
+Bug 2: incorrect font: after the .IP things are roman again.
+*/
+
+#define FO0 ""
+#define FC0 ""
+#define FO1 "<I>"
+#define FC1 "</I>"
+#define FO2 "<B>"
+#define FC2 "</B>"
+#define FO3 "<TT>"
+#define FC3 "</TT>"
+
+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'): break;
+ case 'L': nr=3; break;
+ case 'B': nr=2; break;
+ case 'I': nr=1; break;
+ case 0: case 1: case 2: case 3:
+ break;
+ case 'P': case 'R':
+ 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++]='>';
+ sizebuf[l]=0;
+ }
+ strcat(sizebuf, change_to_font(i));
+ return sizebuf;
+}
+
+int asint=0;
+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="&nbsp;";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="&lt;";curpos++; break;
+ case '>': h="&gt;";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);
+ }
+}
+
+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);
+ c++;
+ if (*c == '(') {
+ c=scan_expression(c+1,&curfield->width);
+ } else {
+ i=0;
+ while (isdigit(*c)) i=i*10+(*c++)-'0';
+ curfield->width=i;
+ }
+ 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;
+ }
+}
+
+char itemreset[20]="\\fR\\s0";
+
+static char *
+scan_table(char *c) {
+ char *h;
+ char *g;
+ int center=0, expand=0, box=0, border=0, linesize=1;
+ int i,j,maxcol=0, finished=0;
+ int oldfont, oldsize,oldfillout;
+ char itemsep='\t';
+ TABLEROW *layout=NULL, *currow;
+ TABLEITEM *curfield;
+ while (*c++!='\n'); /* skip TS */
+ 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 && *c) {
+ /* 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("&nbsp;");
+ 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;
+}
+
+char *scan_expression(char *c, int *result) {
+ int value=0,value2,sign=1,opex=0;
+ char oper='c';
+
+ if (*c=='!') {
+ c=scan_expression(c+1, &value);
+ value= (!value);
+ } else if (*c=='n') {
+ c++;
+ value=nroff;
+ } else if (*c=='t') {
+ c++;
+ value=1-nroff;
+ } else if (*c=='\'' || *c=='"' || *c<' ' || (*c=='\\' && c[1]=='(')) {
+ /* ?string1?string2?
+ ** test if string1 equals string2.
+ */
+ char *st1=NULL, *st2=NULL, *h;
+ char *tcmp=NULL;
+ char sep;
+ sep=*c;
+ if (sep=='\\') {
+ tcmp=c;
+ c=c+3;
+ }
+ c++;
+ h=c;
+ while (*c!= sep && (!tcmp || strncmp(c,tcmp,4))) c++;
+ *c='\n';
+ scan_troff(h, 1, &st1);
+ *c=sep;
+ if (tcmp) c=c+3;
+ c++;
+ h=c;
+ while (*c!=sep && (!tcmp || strncmp(c,tcmp,4))) c++;
+ *c='\n';
+ scan_troff(h,1,&st2);
+ *c=sep;
+ if (!st1 && !st2) value=1;
+ else if (!st1 || !st2) value=0;
+ else value=(!strcmp(st1, st2));
+ if (st1) free(st1);
+ if (st2) free(st2);
+ if (tcmp) c=c+3;
+ c++;
+ } else {
+ while (*c && !isspace(*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 && (*sl != '\n' || slash)) {
+ if (!slash) {
+ if (*sl == escapesym)
+ slash = 1;
+ else if (*sl == s)
+ *sl = t;
+ } else
+ slash = 0;
+ sl++;
+ }
+}
+
+/*
+ * Read STR until end-of-line (not preceded by \).
+ * Find whitespace separated words, and store starts in WORDS of lth MAXN.
+ * Return number of words in N.
+ * Replace each end-of-word by the character EOW (usually \n or 0).
+ * Return pointer to last char seen (either \n or 0).
+ *
+ * A part \"... is skipped.
+ * Quotes not preceded by \ are replaced by \a.
+ */
+static char *
+fill_words(char *str, char *words[], int maxn, int *n, char eow) {
+ char *s = str;
+ int backslash = 0;
+ int skipspace = 0; /* 1 if space is not end-of-word */
+
+ *n = 0;
+ words[*n] = s;
+ while (*s && (*s != '\n' || backslash)) {
+ if (!backslash) {
+ if (*s == '"') {
+ *s = '\a';
+ skipspace = !skipspace;
+ } else if (*s == escapesym) {
+ backslash = 1;
+ } else if ((*s == ' ' || *s == '\t') && !skipspace) {
+ *s = eow;
+ if (words[*n] != s && *n < maxn-1)
+ (*n)++;
+ words[*n] = s+1;
+ }
+ } else {
+ if (*s == '"') {
+ s--;
+ *s = eow;
+ if (words[*n] != s && *n < maxn-1)
+ (*n)++;
+ s++;
+ while (*s && *s != '\n') s++;
+ words[*n] = s;
+ s--;
+ }
+ backslash = 0;
+ }
+ s++;
+ }
+ if (s != words[*n])
+ (*n)++;
+ return s;
+}
+
+
+char *section_list[] = {
+ "1", "User Commands ",
+ "1C", "User Commands",
+ "1G", "User Commands",
+ "1S", "User Commands",
+ "1V", "User Commands ",
+ "2", "System Calls",
+ "2V", "System Calls",
+ "3", "C Library Functions",
+ "3C", "Compatibility Functions",
+ "3F", "Fortran Library Routines",
+ "3K", "Kernel VM Library Functions",
+ "3L", "Lightweight Processes Library",
+ "3M", "Mathematical Library",
+ "3N", "Network Functions",
+ "3R", "RPC Services Library",
+ "3S", "Standard I/O Functions",
+ "3V", "C Library Functions",
+ "3X", "Miscellaneous Library Functions",
+ "4", "Devices and Network Interfaces",
+ "4F", "Protocol Families",
+ "4I", "Devices and Network Interfaces",
+ "4M", "Devices and Network Interfaces",
+ "4N", "Devices and Network Interfaces",
+ "4P", "Protocols",
+ "4S", "Devices and Network Interfaces",
+ "4V", "Devices and Network Interfaces",
+ "5", "File Formats",
+ "5V", "File Formats",
+ "6", "Games and Demos",
+ "7", "Environments, Tables, and Troff Macros",
+ "7V", "Environments, Tables, and Troff Macros",
+ "8", "Maintenance Commands",
+ "8C", "Maintenance Commands",
+ "8S", "Maintenance Commands",
+ "8V", "Maintenance Commands",
+ "L", "Local Commands",
+/* for Solaris:
+ "1", "User Commands",
+ "1B", "SunOS/BSD Compatibility Package Commands",
+ "1b", "SunOS/BSD Compatibility Package Commands",
+ "1C", "Communication Commands ",
+ "1c", "Communication Commands",
+ "1F", "FMLI Commands ",
+ "1f", "FMLI Commands",
+ "1G", "Graphics and CAD Commands ",
+ "1g", "Graphics and CAD Commands ",
+ "1M", "Maintenance Commands",
+ "1m", "Maintenance Commands",
+ "1S", "SunOS Specific Commands",
+ "1s", "SunOS Specific Commands",
+ "2", "System Calls",
+ "3", "C Library Functions",
+ "3B", "SunOS/BSD Compatibility Library Functions",
+ "3b", "SunOS/BSD Compatibility Library Functions",
+ "3C", "C Library Functions",
+ "3c", "C Library Functions",
+ "3E", "C Library Functions",
+ "3e", "C Library Functions",
+ "3F", "Fortran Library Routines",
+ "3f", "Fortran Library Routines",
+ "3G", "C Library Functions",
+ "3g", "C Library Functions",
+ "3I", "Wide Character Functions",
+ "3i", "Wide Character Functions",
+ "3K", "Kernel VM Library Functions",
+ "3k", "Kernel VM Library Functions",
+ "3L", "Lightweight Processes Library",
+ "3l", "Lightweight Processes Library",
+ "3M", "Mathematical Library",
+ "3m", "Mathematical Library",
+ "3N", "Network Functions",
+ "3n", "Network Functions",
+ "3R", "Realtime Library",
+ "3r", "Realtime Library",
+ "3S", "Standard I/O Functions",
+ "3s", "Standard I/O Functions",
+ "3T", "Threads Library",
+ "3t", "Threads Library",
+ "3W", "C Library Functions",
+ "3w", "C Library Functions",
+ "3X", "Miscellaneous Library Functions",
+ "3x", "Miscellaneous Library Functions",
+ "4", "File Formats",
+ "4B", "SunOS/BSD Compatibility Package File Formats",
+ "4b", "SunOS/BSD Compatibility Package File Formats",
+ "5", "Headers, Tables, and Macros",
+ "6", "Games and Demos",
+ "7", "Special Files",
+ "7B", "SunOS/BSD Compatibility Special Files",
+ "7b", "SunOS/BSD Compatibility Special Files",
+ "8", "Maintenance Procedures",
+ "8C", "Maintenance Procedures",
+ "8c", "Maintenance Procedures",
+ "8S", "Maintenance Procedures",
+ "8s", "Maintenance Procedures",
+ "9", "DDI and DKI",
+ "9E", "DDI and DKI Driver Entry Points",
+ "9e", "DDI and DKI Driver Entry Points",
+ "9F", "DDI and DKI Kernel Functions",
+ "9f", "DDI and DKI Kernel Functions",
+ "9S", "DDI and DKI Data Structures",
+ "9s", "DDI and DKI Data Structures",
+ "L", "Local Commands",
+*/
+ NULL, "Misc. Reference Manual Pages",
+ NULL, NULL
+};
+
+static char *
+section_name(char *c)
+{
+ int i=0;
+
+ if (!c) return "";
+ while (section_list[i] && strcmp(c,section_list[i])) i=i+2;
+ if (section_list[i+1]) return section_list[i+1];
+ else return c;
+}
+
+int manidxlen = 0;
+char *manidx = NULL;
+int subs = 0;
+int mip = 0; /* current offset in manidx[] */
+char label[5]="lbAA";
+
+static void
+manidx_need(int m) {
+ if (mip + m >= manidxlen) {
+ manidxlen += 10000;
+ manidx = xrealloc(manidx, manidxlen);
+ }
+}
+
+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) {
+ manidx_need(6);
+ if (subs) {
+ strcpy(manidx+mip, "</DL>\n");
+ mip += 6;
+ } else {
+ strcpy(manidx+mip, "<DL>\n");
+ mip += 5;
+ }
+ }
+ subs = level;
+
+ scan_troff(item, 1, &c);
+ manidx_need(100 + strlen(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;
+}
+
+int ifelseval=0;
+
+static char *
+scan_request(char *c) {
+ /* BSD Mandoc stuff - by Michael Hamilton */
+ 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 */
+ static int inXo=0;
+
+ int i,j,mode = 0;
+ char *h;
+ char *wordlist[20];
+ 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;
+ printf("%s\n", buffer);
+ }
+ fprintf(stderr, "%s\n", c+2); /* XXX */
+ exit(0);
+ break;
+ case V('d','i'):
+ {
+ STRDEF *de;
+ c=c+j;
+ i=V(c[0],c[1]);
+ if (*c == '\n') { c++;break; }
+ while (*c && *c!='\n') c++;
+ c++;
+ h=c;
+ while (*c && strncmp(c,".di",3)) while (*c && *c++!='\n');
+ *c=0;
+ de=strdef;
+ while (de && de->nr !=i) de=de->next;
+ if (!de) {
+ de=(STRDEF*) 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;
+ while (*c == ' ') c++;
+ 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) { /* .ds */
+ char *h=NULL;
+ c=scan_troff(c, 1, &h);
+ free(de->st); /* segfault XXX */
+ de->slen=curpos;
+ de->st=h;
+ } else { /* .as */
+ c=scan_troff(c,1,&de->st); /* XXX */
+ 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'): /* .ig: ignore until .. */
+ {
+ char *endwith="..\n";
+ i=3;
+ c=c+j;
+ while (*c == ' ') c++;
+ if (*c == escapesym && c[1] == '"')
+ while (*c != '\n') c++;
+ if (*c!='\n') { /* .ig yy: ignore until .yy, then call .yy */
+ endwith=c-1;i=1;
+ c[-1]='.';
+ while (*c && *c!='\n') c++,i++;
+ }
+ c++;
+ while (*c && strncmp(c,endwith,i))
+ while (*c && *c++!='\n');
+ while (*c && *c++!='\n');
+ break;
+ }
+ case V('n','f'):
+ if (fillout) {
+ out_html(change_to_font(0));
+ out_html(change_to_size('0'));
+ out_html("<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; char *buf;
+ char *name = NULL;
+
+ curpos=0;
+ c += j; /* skip .so part and whitespace */
+ if (*c == '/') {
+ h = c;
+ } else { /* .so man3/cpow.3 -> ../man3/cpow.3 */
+ h = c-3;
+ h[0] = '.';
+ h[1] = '.';
+ h[2] = '/';
+ }
+ while (*c != '\n') c++;
+ while (c[-1] == ' ') c--;
+ while (*c != '\n') *c++ = 0;
+ *c = 0;
+ scan_troff(h,1, &name);
+ if (name[3] == '/') h=name+3; else h=name;
+ l = 0;
+ if (stat(h, &stbuf)!=-1) l=stbuf.st_size;
+ buf = (char*) xmalloc((l+4)*sizeof(char));
+#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 */
+ if (!l || !(f = fopen(h,"r"))) {
+ 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 {
+ i=fread(buf+1,1,l,f);
+ fclose(f);
+ 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++;
+ if (j+1 < SIZE(tabstops))
+ j++;
+ }
+ maxtstop=j;
+ curpos=0;
+ break;
+ case V('t','i'):
+#if 0
+ dl_down();
+#endif
+ out_html("<BR>\n");
+ c=c+j;
+ c=scan_expression(c, &j);
+ for (i=0; i<j; i++) out_html("&nbsp;");
+ 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); /* XXX */
+ *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, SIZE(wordlist), &words, '\n');
+ 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'):
+ maxtstop = SIZE(tabstops);
+ for (j=0; j<maxtstop; j++)
+ tabstops[j]=(j+1)*8;
+ c=skip_till_newline(c); break;
+ case V('I','P'):
+ sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
+ c = sl+1;
+ dl_begin();
+ if (words) {
+ scan_troff(wordlist[0], 1,NULL);
+ }
+ out_html("<DD>");
+ curpos = 0;
+ break;
+ case V('T','P'):
+ dl_begin();
+ 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, SIZE(wordlist), &words, '\n');
+ c = sl+1;
+ j = 4;
+ while (idxlabel[j] == 'Z') idxlabel[j--]='A';
+ idxlabel[j]++;
+#ifdef MAKEINDEX
+ if (idxfile) {
+ 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 '&nbsp;' 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'):
+ dl_end();
+ 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'):
+ dl_begin();
+ 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, SIZE(wordlist), &words, '\n');
+ j = 1;
+ if (words>0) scan_expression(wordlist[0], &j);
+ if (j>=0) {
+ dl_newlevel();
+ c=skip_till_newline(c);
+ curpos=0;
+ break;
+ }
+ case V('R','e'): /* BSD mandoc */
+ case V('R','E'):
+ dl_endlevel();
+ 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;
+ goto sh_below;
+ case V('S','h'): /* BSD mandoc */
+ mandoc_command = 1;
+ case V('S','H'):
+ sh_below:
+ c=c+j;
+ if (*c == '\n') c++;
+ dl_down();
+ 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);
+ /* &nbsp; for mosaic users */
+ if (mode) out_html("\">&nbsp;</A>\n<H3>");
+ else out_html("\">&nbsp;</A>\n<H2>");
+ mandoc_synopsis = (strncmp(c, "SYNOPSIS", 8) == 0);
+ c = (mandoc_command ? scan_troff_mandoc : scan_troff)(c,1,NULL);
+ if (mode) out_html("</H3>\n");
+ else out_html("</H2>\n");
+ curpos=0;
+ break;
+ case V('T','S'):
+ c=scan_table(c);
+ break;
+ case V('D','t'): /* BSD mandoc */
+ mandoc_command = 1;
+ case V('T','H'):
+ if (!output_possible) {
+ sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, 0);
+ *sl = 0;
+ if (words > 1) {
+ output_possible=1;
+ out_html("<HTML><HEAD><TITLE>Manpage of ");
+ out_html(wordlist[0]);
+ out_html("</TITLE>\n</HEAD><BODY>\n<H1>");
+ out_html(wordlist[0]);
+ out_html("</H1>\nSection: ");
+ if (words>4)
+ out_html(wordlist[4]);
+ else
+ out_html(section_name(wordlist[1]));
+ out_html(" (");
+ out_html(wordlist[1]);
+ if (words>2) {
+ out_html(")<BR>Updated: ");
+ scan_troff(wordlist[2], 1, NULL);
+ } else out_html(")");
+ out_html("<BR><A HREF=\"#index\">Index</A>\n");
+ man_page_html(0,0); /* Return to Main Contents */
+ *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, SIZE(wordlist), &words, '\n');
+ *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, SIZE(wordlist), &words, '\n');
+ 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= (char*) xmalloc((j*2+4)*sizeof(char));
+ 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;
+
+ /* ----- BSD mandoc stuff below ----- */
+ case V('U','x'): /* BSD mandoc */
+ c=c+j;
+ out_html("UNIX");
+ c=skip_till_newline(c);
+ break;
+ case V('A','t'): /* BSD mandoc - called with arg V */
+ c=c+j;
+ out_html("AT&amp;T System");
+ break;
+ case V('B','l'): /* BSD mandoc */
+ {
+ char *nl, t=0 /* just for gcc */;
+ c=c+j;
+ nl = strchr(c,'\n');
+ if (nl) {
+ t = *nl;
+ *nl = 0;
+ }
+ if (strstr(c, "-bullet")) /* HTML Unnumbered List */
+ dl_newlevel_type(UL);
+ else if (strstr(c, "-enum")) /* HTML Ordered List */
+ dl_newlevel_type(OL);
+ else /* HTML Descriptive List */
+ dl_newlevel_type(DL);
+ if (nl)
+ *nl = t;
+ 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;
+ dl_endlevel_type();
+ 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 (dl_type(DL)) {
+ 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);
+ if (inXo)
+ still_dd = 1;
+ else
+ out_html("<DD>");
+ } else if (dl_type(UL) || dl_type(OL)) {
+ out_html("<LI>");
+ c=scan_troff_mandoc(c,1,NULL);
+ out_html(NEWLINE);
+ }
+ if (fillout) curpos++; else curpos=0;
+ break;
+ case V('X','o'): /* BSD mandoc */
+ c=c+j;
+ inXo = 1;
+ break;
+ case V('X','c'): /* BSD mandoc - Xc closes an Xo */
+ c=c+j;
+ if (inXo) {
+ if (still_dd)
+ out_html("<DD>");
+ inXo = 0;
+ }
+ break;
+ case V('S','m'): /* BSD mandoc - called with arg on/off */
+ c=skip_till_newline(c);
+ 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 *nl, t=0 /* just for gcc */;
+ c=c+j;
+ nl = strchr(c,'\n');
+ if (nl) {
+ t = *nl;
+ *nl = 0;
+ }
+ out_html(NEWLINE);
+ mandoc_bd_options = 0; /* Remember options for terminating Bl */
+ if (strstr(c, "-offset indent")) {
+ mandoc_bd_options |= BD_INDENT;
+ out_html("<BLOCKQUOTE>\n");
+ }
+ if (strstr(c, "-literal") || strstr(c, "-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;
+ }
+ if (nl)
+ *nl = t;
+ 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[100];
+ 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) && bufptr < buff + SIZE(buff)-4) {
+ /* Copy the xyz part */
+ *bufptr++ = *c++;
+ }
+ while (isspace(*c) && *c != '\n') c++; /* Skip spaces */
+ if (isdigit(*c)) { /* Convert the number if there is one */
+ *bufptr++ = '(';
+ while (isalnum(*c) && bufptr < buff + SIZE(buff)-3) {
+ *bufptr++ = *c++;
+ }
+ *bufptr++ = ')';
+ }
+ while (*c != '\n' && bufptr < buff + SIZE(buff)-2) {
+ /* Copy the remainder */
+ if (!isspace(*c)) {
+ *bufptr++ = *c;
+ }
+ c++;
+ }
+ *bufptr++ = '\n';
+ *bufptr = 0;
+ 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 */
+ /* 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 = 0;
+ 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, t=0 /* just for gcc */;
+ end = strchr(c, '\n');
+ if (end) {
+ t = *end;
+ *end = 0;
+ }
+ if (mandoc_name)
+ free(mandoc_name);
+ mandoc_name = xstrdup(c);
+ if (end)
+ *end = t;
+ }
+ 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.
+ */
+ if (mandoc_name)
+ 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;
+ /* ----- end of BSD mandoc stuff ----- */
+
+ 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, SIZE(wordlist), &words, '\n');
+ 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<SIZE(wordlist); i++)
+ wordlist[i]=NULL;
+ deflen = strlen(owndef->st);
+ owndef->st[deflen+1]='a';
+ 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 dealt 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++; /* really? */
+ 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 int contained_tab=0;
+static int mandoc_line=0;/* Signals whether to look for embedded mandoc cmds */
+
+static char *
+scan_troff(char *c, int san, char **result) { /* san : stop at newline */
+ char *h;
+ char intbuff[500];
+ int ibp=0;
+#define FLUSHIBP if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
+ char *exbuffer;
+ int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun;
+ int usenbsp = 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 = (char *) xmalloc(1000*sizeof(char));
+ buffpos = 0;
+ buffmax = 1000;
+ }
+ 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 {
+ 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[SIZE(tabstops)-1] = 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("&nbsp;");
+ 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("&nbsp;"); else intbuff[ibp++]=' ';
+ } else if (*h > 31 && *h < 127) {
+ intbuff[ibp++]=*h;
+ } else if (((unsigned char)(*h)) > 127) {
+#ifdef NO_8BIT
+ 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++]=';';
+#else
+ intbuff[ibp++]=*h;
+#endif
+ }
+ curpos++;
+ break;
+ }
+ if (ibp>480) 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;
+}
+
+STRDEF *foundpages=NULL;
+
+static void
+error_page(char *s, char *t, ...) {
+ va_list p;
+
+ printf("<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n"
+ "<BODY>\n<H1>%s</H1>\n", s, s);
+ va_start(p, t);
+ vfprintf(stdout, t, p);
+ va_end(p);
+ printf("</BODY></HTML>\n");
+ exit(0);
+}
+
+char *
+xstrdup(const char *s) {
+ char *p = strdup(s);
+ if (p == NULL)
+ error_page("Out of memory",
+ "Sorry, out of memory, aborting...\n");
+ return p;
+}
+
+void *
+xmalloc(size_t size) {
+ void *p = malloc(size);
+ if (p == NULL)
+ error_page("Out of memory",
+ "Sorry, out of memory, aborting...\n");
+ return p;
+}
+
+void *
+xrealloc(void *ptr, size_t size) {
+ void *p = realloc(ptr,size);
+ if (p == NULL)
+ error_page("Out of memory",
+ "Sorry, out of memory, aborting...\n");
+ return p;
+}
+
+static void
+usage(void) {
+ error_page("man2html: bad invocation",
+ "Call: man2html [-l|-h host.domain:port] [-p|-q] [filename]\n"
+ "or: man2html -r [filename]\n");
+}
+
+static void
+goto_dir(char *path, char **dir, char **name) {
+ char *s, *t, *u;
+
+ s = xstrdup(path);
+ t = strrchr(s, '/');
+ if (t) {
+ *t = 0;
+ u = strrchr(s, '/');
+ *t = '/';
+ if (u) {
+ *u = 0;
+ if (chdir(s) == 0) {
+ if (dir)
+ *dir = s;
+ if (name)
+ *name = u+1;
+ }
+#if 0
+ else /* complain or not - this need not be fatal */
+ error_page("Error", "man2html: could not chdir to %s", s);
+#endif
+ }
+ }
+}
+
+/*
+ * Call: man2html [-l] [filename]
+ *
+ * The contents of FILENAME (or STDIN, in case FILENAME is "-" or absent)
+ * are converted from man-style nroff to html, and printed on STDOUT.
+ *
+ * Possible errors are reflected in the output. The return status is 0.
+ */
+int
+main(int argc, char **argv) {
+ FILE *f;
+ struct stat stbuf;
+ int l, c;
+ char *buf, *filename, *fnam = NULL;
+
+#ifdef __CYGWIN__
+ int opterr;
+
+ extern int optind;
+ extern char *optarg;
+#endif
+
+ printf("Content-type: text/html\n\n");
+
+ opterr = 0; /* no stderr error messages */
+ while ((c = getopt (argc, argv, "D:E:hH:lL:M:pqr?vVf")) != -1) {
+ switch(c) {
+ case 'D':
+ goto_dir(optarg, 0, 0); break;
+ case 'E':
+ error_page("Error", "%s", optarg); break;
+ case 'h':
+ set_cgibase("localhost"); break;
+ case 'H':
+ set_cgibase(optarg); break;
+ case 'l':
+ set_lynxcgibase("/home/httpd"); break;
+ case 'L':
+ set_lynxcgibase(optarg); break;
+ case 'M':
+ set_man2htmlpath(optarg); break;
+ case 'p':
+ set_separator('/'); break;
+ case 'q':
+ set_separator('?'); break;
+ case 'r':
+ set_relative_html_links(); break;
+ case 'v':
+ case 'V':
+ error_page("Version", "%s from man-%s", argv[0], version);
+ exit(0);
+ case '?':
+ default:
+ usage();
+ case 'f': /* It is rumoured that some other
+ incarnation of man2html uses this flag;
+ ignore when given for compatibility. */
+ /* case 'F': this will assign a format for man_page_html() */
+ break;
+ }
+ }
+
+ /* Find filename */
+ if (argc == optind+1)
+ fnam = argv[optind];
+ else if (argc != optind)
+ usage();
+
+ filename = fnam;
+ directory = 0;
+
+ /* Open input file */
+ if (!fnam || !strcmp(fnam, "-")) {
+ f = stdin;
+ fname = "(stdin)";
+ } else {
+ /* do a chdir() first, to get .so expansion right */
+ goto_dir(fnam, &directory, &fnam);
+
+ f = fopen(fnam, "r");
+ if (f == NULL)
+ error_page("File not found", "Could not open %s\n", filename);
+ fname = fnam;
+ }
+
+ /* Read entire file into buf[1..l] */
+#define XTRA 5
+ /* buf has 1 extra byte at the start, and XTRA extra bytes at the end */
+ if (f == stdin) {
+ int sz = 1024;
+ int ct = 1, tot = 0;
+ char *p = NULL;
+
+ clearerr(stdin);
+ while (ct > 0) {
+ tot += ct;
+ if (feof(stdin))
+ break;
+ sz = 2*sz+tot;
+ p = xrealloc(p, sz);
+ ct = fread(p+tot,1,sz-tot-XTRA,stdin);
+ }
+
+ buf = p;
+ l = tot-1;
+ } else {
+ int ct;
+
+ l = 0;
+ if (fstat(fileno(f), &stbuf) != -1)
+ l = stbuf.st_size;
+ buf = (char *) xmalloc((l+1+XTRA)*sizeof(char));
+ ct = fread(buf+1,1,l,f);
+ if (ct < l)
+ l = ct;
+ fclose(f);
+ }
+
+ buf[0] = '\n';
+ buf[l+1] = '\n';
+ buf[l+2] = buf[l+3] = 0;
+
+#ifdef MAKEINDEX
+ idxfile = fopen(INDEXFILE, "a");
+#endif
+ stdinit();
+
+ scan_troff(buf+1,0,NULL);
+ dl_down();
+ 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) {
+ /* &nbsp; for mosaic users */
+ printf("<HR>\n<A NAME=\"index\">&nbsp;</A><H2>Index</H2>\n<DL>\n");
+ manidx[mip]=0;
+ printf("%s", manidx);
+ if (subs) printf("</DL>\n");
+ printf("</DL>\n");
+ print_sig();
+ printf("</BODY>\n</HTML>\n");
+ } else {
+ if (!filename)
+ filename = fname;
+ if (*filename == '/')
+ error_page("Invalid Manpage",
+ "The requested file %s is not a valid (unformatted) "
+ "man page.\nIf the file is a formatted manpage, "
+ "you could try to load the\n"
+ "<A HREF=\"file://localhost%s\">plain file</A>.\n",
+ filename, filename);
+ else
+ error_page("Invalid Manpage",
+ "The requested file %s is not a valid (unformatted) "
+ "man page.", filename);
+ }
+ if (idxfile)
+ fclose(idxfile);
+ if (buf)
+ free(buf);
+ return 0;
+}