Subversion Repositories Kolibri OS

Rev

Rev 9278 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2. ** This program was written by Richard Verhoeven (NL:5482ZX35)
  3. ** at the Eindhoven University of Technology. Email: rcb5@win.tue.nl
  4. **
  5. ** Permission is granted to distribute, modify and use this program
  6. ** as long as this comment is not removed or changed.
  7. */
  8.  
  9. /* BSD mandoc stuff added by Michael Hamilton. */
  10.  
  11. /* This program is rather buggy, but in spite of that it often works.
  12.    Improved things a little - April 1997 & January 1998 & Dec 2001 -
  13.    aeb@cwi.nl. */
  14.  
  15. /* some code added by Tsukasa Hamnao. */
  16.  
  17. #include <stdlib.h>
  18. #include <stdarg.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <libgen.h>
  22.  
  23. #ifdef _KOLIBRI
  24. #include <sys/ksys.h>
  25. #include <sys/dir.h>
  26. #else
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #endif
  30.  
  31. #include "defs.h"
  32. static char version[] = "1.6f-1";
  33.  
  34. /* BSD mandoc Bd/Ed example(?) blocks */
  35. #define BD_LITERAL  1
  36. #define BD_INDENT   2
  37.  
  38. #define SIZE(a)    (sizeof(a)/sizeof(*a))
  39.  
  40. static char NEWLINE[2]="\n";
  41. static char idxlabel[6] = "ixAAA";
  42.  
  43. #ifdef _KOLIBRI
  44.     #define INDEXFILE "/tmp0/1/manindex.list"
  45. #else
  46.     #define INDEXFILE "./manindex.list"
  47. #endif
  48.  
  49. char *fname;
  50. //char *directory;
  51. FILE *idxfile;
  52.  
  53. char eqndelimopen=0, eqndelimclose=0;
  54. char escapesym='\\', nobreaksym='\'', controlsym='.', fieldsym=0, padsym=0;
  55.  
  56. char *buffer=NULL;
  57. int buffpos=0, buffmax=0;
  58. int scaninbuff=0;
  59. int still_dd=0;
  60. int tabstops[20] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
  61. int maxtstop=12;
  62. int curpos=0;
  63.  
  64. static char *scan_troff(char *c, int san, char **result);
  65. static char *scan_troff_mandoc(char *c, int san, char **result);
  66.  
  67. static char **argument=NULL;
  68.  
  69. static char charb[3];
  70.  
  71. FILE *out;
  72.  
  73. static char *
  74. expand_char(int nr)
  75. {
  76.     STRDEF *h;
  77.  
  78.     if (!nr)
  79.         return NULL;
  80.  
  81.     h = chardef;
  82.     if (h->nr != V('*','*')) {
  83.         fprintf(out, "chardef corrupted\n");
  84.         exit(1);
  85.     }
  86.  
  87.     for (h = chardef; h; h = h->next)
  88.         if (h->nr == nr) {
  89.             curpos += h->slen;
  90.             return h->st;
  91.         }
  92.     charb[0] = nr/256;
  93.     charb[1] = nr%256;
  94.     charb[2] = 0;
  95.     curpos += 2;
  96.     return charb;
  97. }
  98.  
  99. static char *
  100. expand_string(int nr)
  101. {
  102.     STRDEF *h;
  103.  
  104.     if (!nr)
  105.         return NULL;
  106.     for (h = strdef; h; h = h->next)
  107.         if (h->nr == nr) {
  108.             curpos += h->slen;
  109.             return h->st;
  110.         }
  111.     return NULL;
  112. }
  113.  
  114.  
  115. static char outbuffer[1024];
  116. static int obp=0;
  117. static int no_newline_output=0;        /* boolean, set by \c */
  118. static int newline_for_fun=0;
  119. static int output_possible=0;
  120. static int out_length=0;
  121.  
  122. static void
  123. add_links(char *c)
  124. {
  125.     /*
  126.     ** Add the links to the output.
  127.     ** At the moment the following are recognized:
  128.     **
  129.     ** name(*)                 -> ../man?/name.*
  130.     ** method://string         -> method://string
  131.     ** www.host.name           -> http://www.host.name
  132.     ** ftp.host.name           -> ftp://ftp.host.name
  133.     ** name@host               -> mailto:name@host
  134.     ** <name.h>                -> file:/usr/include/name.h   (guess)
  135.     **
  136.     ** Other possible links to add in the future:
  137.     **
  138.     ** /dir/dir/file  -> file:/dir/dir/file
  139.     */
  140.     int i,j,nr;
  141.     char *f, *g, *h;
  142.     char *idtest[6]; /* url, mailto, www, ftp, manpage, include file */
  143.  
  144.     out_length+=strlen(c);
  145.  
  146.     nr=0;
  147.     idtest[0]=strstr(c+1,"://");
  148.     /* idtest[1]=strchr(c+1,'@'); */
  149.     idtest[1]=NULL; /* don't create mailto links. */
  150.     idtest[2]=strstr(c,"www.");
  151.     idtest[3]=strstr(c,"ftp.");
  152.     idtest[4]=strchr(c+1,'(');
  153.     idtest[5]=strstr(c+1,".h&gt;");
  154.     for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
  155.     while (nr) {
  156.     j=-1;
  157.     for (i=0; i<6; i++)
  158.         if (idtest[i] && (j<0 || idtest[i]<idtest[j])) j=i;
  159.     switch (j) {
  160.     case 5: /* <name.h> */
  161.         f=idtest[5];
  162.         h=f+2;
  163.         g=f;
  164.         while (g>c && g[-1]!=';') g--;
  165.         if (g!=c) {
  166.         char t;
  167.         t=*g;
  168.         *g=0;
  169.         fprintf(out, "%s",c);
  170.         *g=t;*h=0;
  171.         include_file_html(g);
  172.         c=f+6;
  173.         } else {
  174.         f[5]=0;
  175.         fprintf(out, "%s",c);
  176.         f[5]=';';
  177.         c=f+5;
  178.         }
  179.         break;
  180.     case 4:            /* manpage? */
  181.         f=idtest[j];
  182.         /* find section - accept (1), (3F), (3Xt), (n), (l) */
  183.         g=strchr(f,')');
  184.         if (g && g-f<7    /* section has length at most 5, like 3Xlib */
  185.                         /* preceded by name or html markup */
  186.           && (isalnum(f[-1]) || f[-1]=='>')
  187.                                 /* section is n or l or starts with a digit */
  188.           && strchr("123456789nl", f[1])
  189.           && (g-f == 2 || (g-f == 3 && isdigit(f[1]) && isalpha(f[2]))
  190.                        || (f[2] == 'X' && isdigit(f[1])))
  191.            ) {
  192.         /* this might be a link */
  193.         h=f-1;
  194.         /* skip html markup */
  195.         while (h>c && *h=='>') {
  196.             while (h!=c && *h!='<') h--;
  197.             if (h!=c) h--;
  198.         }
  199.         if (isalnum(*h)) {
  200.             char t,te,tg,*e;
  201.             e=h+1;
  202.             while (h>c && (isalnum(h[-1]) || h[-1]=='_' ||
  203.                     h[-1]=='-' || h[-1]=='.' || h[-1]==':'))
  204.             h--;
  205.             t=*h; *h=0;
  206.             fprintf(out, "%s", c);
  207.             *h=t;
  208.             tg=*g; *g=0;
  209.             te=*e; *e=0;
  210.             man_page_html(f+1, h);     /* section, page */
  211.             *e=te;
  212.             *g=tg;
  213.             c=e;
  214.         }
  215.         }
  216.         *f=0;
  217.         fprintf(out, "%s", c);
  218.         *f='(';
  219.         idtest[4]=f-1;
  220.         c=f;
  221.         break; /* manpage */
  222.     case 3: /* ftp */
  223.     case 2: /* www */
  224.         g=f=idtest[j];
  225.         while (*g && (isalnum(*g) || *g=='_' || *g=='-' || *g=='+' ||
  226.               *g=='.')) g++;
  227.         if (g[-1]=='.') g--;
  228.         if (g-f>4) {
  229.         char t;
  230.         t=*f; *f=0;
  231.         fprintf(out, "%s",c);
  232.         *f=t; t=*g;*g=0;
  233.         if (j==3)
  234.              ftp_html(f);
  235.         else
  236.              www_html(f);
  237.         *g=t;
  238.         c=g;
  239.         } else {
  240.         f[3]=0;
  241.         fprintf(out, "%s",c);
  242.         c=f+3;
  243.         f[3]='.';
  244.         }
  245.         break;
  246.     case 1: /* mailto */
  247.         g=f=idtest[1];
  248.         while (g>c && (isalnum(g[-1]) || g[-1]=='_' || g[-1]=='-' ||
  249.                g[-1]=='+' || g[-1]=='.' || g[-1]=='%')) g--;
  250.         h=f+1;
  251.         while (*h && (isalnum(*h) || *h=='_' || *h=='-' || *h=='+' ||
  252.               *h=='.')) h++;
  253.         if (h[-1]=='.') h--;
  254.         if (h-f>4 && f-g>1) {
  255.         char t;
  256.         t=*g;
  257.         *g=0;
  258.         fprintf(out, "%s",c);
  259.         *g=t;t=*h;*h=0;
  260.         mailto_html(g);
  261.         *h=t;
  262.         c=h;
  263.         } else {
  264.         *f=0;
  265.         fprintf(out, "%s",c);
  266.         *f='@';
  267.         idtest[1]=c;
  268.         c=f;
  269.         }
  270.         break;
  271.     case 0: /* url */
  272.         g=f=idtest[0];
  273.         while (g>c && isalpha(g[-1]) && islower(g[-1])) g--;
  274.         h=f+3;
  275.         while (*h && !isspace(*h) && *h!='<' && *h!='>' && *h!='"' &&
  276.            *h!='&') h++;
  277.         if (f-g>2 && f-g<7 && h-f>3) {
  278.         char t;
  279.         t=*g;
  280.         *g=0;
  281.         fprintf(out, "%s", c);
  282.         *g=t; t=*h; *h=0;
  283.         url_html(g);
  284.         *h=t;
  285.         c=h;
  286.         } else {
  287.         f[1]=0;
  288.         fprintf(out, "%s", c);
  289.         f[1]='/';
  290.         c=f+1;
  291.         }
  292.         break;
  293.     default:
  294.         break;
  295.     }
  296.     nr=0;
  297.     if (idtest[0] && idtest[0]<c) idtest[0]=strstr(c+1,"://");
  298.     if (idtest[1] && idtest[1]<c) idtest[1]=strchr(c+1,'@');
  299.     if (idtest[2] && idtest[2]<c) idtest[2]=strstr(c,"www.");
  300.     if (idtest[3] && idtest[3]<c) idtest[3]=strstr(c,"ftp.");
  301.     if (idtest[4] && idtest[4]<c) idtest[4]=strchr(c+1,'(');
  302.     if (idtest[5] && idtest[5]<c) idtest[5]=strstr(c+1,".h&gt;");
  303.     for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
  304.     }
  305.     fprintf(out, "%s", c);
  306. }
  307.  
  308. int current_font=0;
  309. int current_size=0;
  310. int fillout = 1;
  311.  
  312. /*
  313.  * Kludge: remove \a - in the context
  314.  *   .TH NAME 2 date "Version" "Title"
  315.  * we got output \aTitle\a.
  316.  */
  317. static void
  318. out_html(char *c) {
  319.     if (!c)
  320.         return;
  321.     if (no_newline_output) {    /* remove \n if present */
  322.         int i=0;
  323.         while (c[i]) {
  324.             if (!no_newline_output)
  325.                 c[i-1]=c[i];
  326.             if (c[i]=='\n')
  327.                 no_newline_output=0;
  328.             i++;
  329.         }
  330.         if (!no_newline_output)
  331.             c[i-1]=0;
  332.     }
  333.     if (scaninbuff) {
  334.         while (*c) {
  335.             if (buffpos >= buffmax) {
  336.                 buffer = xrealloc(buffer, buffmax*2);
  337.                 buffmax = buffmax*2;
  338.             }
  339.             if (*c != '\a')
  340.                 buffer[buffpos++] = *c;
  341.             c++;
  342.         }
  343.     } else if (output_possible) {
  344.         while (*c) {
  345.             if (*c != '\a')
  346.                 outbuffer[obp++] = *c;
  347.             if (*c == '\n' || obp > 1000) {
  348.                 outbuffer[obp] = 0;
  349.                 add_links(outbuffer);
  350.                 obp = 0;
  351.             }
  352.             c++;
  353.         }
  354.     }
  355. }
  356.  
  357. /* --------------------------------------------------------------- */
  358. /* All references to dl_set and itemdepth are here.                */
  359. /* --------------------------------------------------------------- */
  360. static int itemdepth=0;
  361. static int dl_set[30]= { 0 };
  362. #define noDL  0
  363. #define DL    1
  364. #define UL    2
  365. #define OL    3
  366. static char *dl_open[4] = { "", "<DL COMPACT>\n", "<UL>", "<OL>" };
  367. static char *dl_close[4] = { "", "</DL>\n", "</UL>", "</OL>" };
  368.  
  369. static inline void
  370. dl_begin(void) {
  371.      if (itemdepth < SIZE(dl_set) && dl_set[itemdepth] == noDL) {
  372.       out_html(dl_open[DL]);
  373.       dl_set[itemdepth]=DL;
  374.      }
  375.      out_html("<DT>");
  376. }
  377.  
  378. static inline void
  379. dl_end(void) {
  380.      if (itemdepth < SIZE(dl_set)) {
  381.       int type = dl_set[itemdepth];
  382.       if (type == DL) {
  383.            out_html(dl_close[type]);
  384.            dl_set[itemdepth]=noDL;
  385.       }
  386.      }
  387. }
  388.  
  389. static inline void
  390. dl_newlevel(void) {
  391.      itemdepth++;
  392.      if (itemdepth < SIZE(dl_set))
  393.       dl_set[itemdepth]=noDL;
  394.      out_html("<DL COMPACT><DT><DD>");
  395. }
  396.  
  397. static inline void
  398. dl_endlevel(void) {
  399.      if (itemdepth) {
  400.       dl_end();
  401.       out_html("</DL>\n");
  402.       itemdepth--;
  403.      }
  404. }
  405.  
  406. static inline void
  407. dl_down(void) {
  408.      while (itemdepth)
  409.       dl_endlevel();
  410.      dl_end();
  411. }
  412.  
  413. static inline int
  414. dl_type(int type) {
  415.      return (itemdepth < SIZE(dl_set) && dl_set[itemdepth] == type);
  416. }
  417.  
  418. static inline void
  419. dl_newlevel_type(int type) {
  420.      itemdepth++;
  421.      if (itemdepth < SIZE(dl_set)) {
  422.       dl_set[itemdepth]=type;
  423.       out_html(dl_open[type]);
  424.      }
  425. }
  426.  
  427. static inline void
  428. dl_endlevel_type(void) {
  429.      if (itemdepth) {
  430.       if (itemdepth < SIZE(dl_set))
  431.            out_html(dl_close[dl_set[itemdepth]]);
  432.       itemdepth--;
  433.      }
  434. }
  435. /* --------------------------------------------------------------- */
  436. /* This stuff is broken.
  437. It generates
  438.    <DT><B>TIOCLINUX, subcode=0<DD>
  439.    Dump the screen.
  440.    </B><I>argp</I> points to a
  441. from
  442.    .IP "\fBTIOCLINUX, subcode=0"
  443.    Dump the screen.
  444.    \fIargp\fP points to a
  445. Bug 1: incorrect nesting: </B> is needed before <DD>.
  446. Bug 2: incorrect font: after the .IP things are roman again.
  447. */
  448.  
  449. #define FO0 ""
  450. #define FC0 ""
  451. #define FO1 "<I>"
  452. #define FC1 "</I>"
  453. #define FO2 "<B>"
  454. #define FC2 "</B>"
  455. #define FO3 "<TT>"
  456. #define FC3 "</TT>"
  457.  
  458. char *switchfont[16] = { "", FC0 FO1, FC0 FO2, FC0 FO3,
  459.                          FC1 FO0, "", FC1 FO2, FC1 FO3,
  460.                          FC2 FO0, FC2 FO1, ""     , FC2 FO3,
  461.                          FC3 FO0, FC3 FO1, FC3 FO2, ""};
  462.  
  463. static char *
  464. change_to_font(int nr)
  465. {
  466.   int i;
  467.   switch (nr) {
  468.   case '0': nr++;
  469.   case '1': case '2': case '3': case '4':
  470.        nr = nr-'1'; break;
  471.   case V('C','W'): nr=3; break;
  472.   case 'L': nr=3; break;
  473.   case 'B': nr=2; break;
  474.   case 'I': nr=1; break;
  475.   case 0: case 1: case 2: case 3:
  476.        break;
  477.   case 'P': case 'R':
  478.   default: nr=0; break;
  479.   }
  480.   i= current_font*4+nr%4;
  481.   current_font=nr%4;
  482.   return switchfont[i];
  483. }
  484.  
  485. static char sizebuf[200];
  486.  
  487. static char *
  488. change_to_size(int nr)
  489. {
  490.   int i;
  491.   switch (nr) {
  492.   case '0': case '1': case '2': case '3': case '4': case '5': case '6':
  493.   case '7': case '8': case '9': nr=nr-'0'; break;
  494.   case '\0': break;
  495.   default: nr=current_size+nr; if (nr>9) nr=9; if (nr< -9) nr=-9; break;
  496.   }
  497.   if (nr==current_size) return "";
  498.   i=current_font;
  499.   sizebuf[0]=0;
  500.   strcat(sizebuf, change_to_font(0));
  501.   if (current_size) strcat(sizebuf, "</FONT>");
  502.   current_size=nr;
  503.   if (nr) {
  504.     int l;
  505.     strcat(sizebuf, "<FONT SIZE=\"");
  506.     l=strlen(sizebuf);
  507.     if (nr>0) sizebuf[l++]='+'; else sizebuf[l++]='-',nr=-nr;
  508.     sizebuf[l++]=nr+'0';
  509.     sizebuf[l++]='"';
  510.     sizebuf[l++]='>';
  511.     sizebuf[l]=0;
  512.   }
  513.   strcat(sizebuf, change_to_font(i));
  514.   return sizebuf;
  515. }
  516.  
  517. int asint=0;
  518. int intresult=0;
  519.  
  520. #define SKIPEOL while (*c && *c++!='\n')
  521.  
  522. static int skip_escape=0;
  523. static int single_escape=0;
  524.  
  525. static char *
  526. scan_escape(char *c) {
  527.     char *h=NULL;
  528.     char b[5];
  529.     INTDEF *intd;
  530.     int exoutputp,exskipescape;
  531.     int i,j;
  532.  
  533.     intresult=0;
  534.     switch (*c) {
  535.     case 'e': h="\\"; curpos++;break;
  536.     case '0':
  537.     case ' ': h="&nbsp;";curpos++; break;
  538.     case '|': h=""; break;
  539.     case '"': SKIPEOL; c--; h=""; break;
  540.     case '$':
  541.     if (argument) {
  542.         c++;
  543.         i=(*c -'1');
  544.         if (!(h=argument[i])) h="";
  545.     }
  546.     break;
  547.     case 'z':
  548.     c++;
  549.     if (*c=='\\') { c=scan_escape(c+1); c--;h=""; }
  550.     else {
  551.         b[0]=*c;
  552.         b[1]=0;
  553.         h="";
  554.     }
  555.     break;
  556.     case 'k': c++; if (*c=='(') c+=2;
  557.     case '^':
  558.     case '!':
  559.     case '%':
  560.     case 'a':
  561.     case 'd':
  562.     case 'r':
  563.     case 'u':
  564.     case '\n':
  565.     case '&': h=""; break;
  566.     case '(':
  567.     c++;
  568.     i= c[0]*256+c[1];
  569.     c++;
  570.     h = expand_char(i);
  571.     break;
  572.     case '*':
  573.     c++;
  574.     if (*c=='(') {
  575.         c++;
  576.         i= c[0]*256+c[1];
  577.         c++;
  578.     } else
  579.         i= *c *256+' ';
  580.     h = expand_string(i);
  581.     break;
  582.     case 'f':
  583.     c++;
  584.     if (*c=='\\') {
  585.         c++;
  586.         c=scan_escape(c);
  587.         c--;
  588.         i=intresult;
  589.     } else     if (*c != '(')
  590.         i=*c;
  591.     else {
  592.         c++;
  593.         i=c[0]*256+c[1];
  594.         c++;
  595.     }
  596.     if (!skip_escape) h=change_to_font(i); else h="";
  597.     break;
  598.     case 's':
  599.     c++;
  600.     j=0;i=0;
  601.     if (*c=='-') {j= -1; c++;} else if (*c=='+') {j=1; c++;}
  602.     if (*c=='0') c++; else if (*c=='\\') {
  603.         c++;
  604.         c=scan_escape(c);
  605.         i=intresult; if (!j) j=1;
  606.     } else
  607.         while (isdigit(*c) && (!i || (!j && i<4))) i=i*10+(*c++)-'0';
  608.     if (!j) { j=1; if (i) i=i-10; }
  609.     if (!skip_escape) h=change_to_size(i*j); else h="";
  610.     c--;
  611.     break;
  612.     case 'n':
  613.     c++;
  614.     j=0;
  615.     switch (*c) {
  616.     case '+': j=1; c++; break;
  617.     case '-': j=-1; c++; break;
  618.     default: break;
  619.     }
  620.     if (*c=='(') {
  621.         c++;
  622.         i=V(c[0],c[1]);
  623.         c=c+1;
  624.     } else {
  625.         i=V(c[0],' ');
  626.     }
  627.     intd=intdef;
  628.     while (intd && intd->nr!=i) intd=intd->next;
  629.     if (intd) {
  630.         intd->val=intd->val+j*intd->incr;
  631.         intresult=intd->val;
  632.     } else {
  633.         switch (i) {
  634.         case V('.','s'): intresult=current_size; break;
  635.         case V('.','f'): intresult=current_font; break;
  636.         default: intresult=0; break;
  637.         }
  638.     }
  639.     h="";
  640.     break;
  641.     case 'w':
  642.     c++;
  643.     i=*c;
  644.     c++;
  645.     exoutputp=output_possible;
  646.     exskipescape=skip_escape;
  647.     output_possible=0;
  648.     skip_escape=1;
  649.     j=0;
  650.     while (*c!=i) {
  651.         j++;
  652.         if (*c==escapesym) c=scan_escape(c+1); else c++;
  653.     }
  654.     output_possible=exoutputp;
  655.     skip_escape=exskipescape;
  656.     intresult=j;
  657.     break;
  658.     case 'l': h="<HR>"; curpos=0;
  659.     case 'b':
  660.     case 'v':
  661.     case 'x':
  662.     case 'o':
  663.     case 'L':
  664.     case 'h':
  665.     c++;
  666.     i=*c;
  667.     c++;
  668.     exoutputp=output_possible;
  669.     exskipescape=skip_escape;
  670.     output_possible=0;
  671.     skip_escape=1;
  672.     while (*c != i)
  673.         if (*c==escapesym) c=scan_escape(c+1);
  674.         else c++;
  675.     output_possible=exoutputp;
  676.     skip_escape=exskipescape;
  677.     break;
  678.     case 'c': no_newline_output=1; break;
  679.     case '{': newline_for_fun++; h="";break;
  680.     case '}': if (newline_for_fun) newline_for_fun--; h="";break;
  681.     case 'p': h="<BR>\n";curpos=0; break;
  682.     case 't': h="\t";curpos=(curpos+8)&0xfff8; break;
  683.     case '<': h="&lt;";curpos++; break;
  684.     case '>': h="&gt;";curpos++; break;
  685.     case '\\': if (single_escape) { c--; break;}
  686.     default: b[0]=*c; b[1]=0; h=b; curpos++; break;
  687.     }
  688.     c++;
  689.     if (!skip_escape) out_html(h);
  690.     return c;
  691. }
  692.  
  693. typedef struct TABLEITEM TABLEITEM;
  694.  
  695. struct TABLEITEM {
  696.     char *contents;
  697.     int size,align,valign,colspan,rowspan,font,vleft,vright,space,width;
  698.     TABLEITEM *next;
  699. };
  700.  
  701. static TABLEITEM emptyfield = {NULL,0,0,0,1,1,0,0,0,0,0,NULL};
  702. typedef struct TABLEROW TABLEROW;
  703.  
  704. struct TABLEROW {
  705.     TABLEITEM *first;
  706.     TABLEROW *prev, *next;
  707. };
  708.  
  709. static char *tableopt[]= { "center", "expand", "box", "allbox", "doublebox",
  710.                "tab", "linesize", "delim", NULL };
  711. static int tableoptl[] = { 6,6,3,6,9,3,8,5,0};
  712.  
  713.  
  714. static void clear_table(TABLEROW *table)
  715. {
  716.     TABLEROW *tr1,*tr2;
  717.     TABLEITEM *ti1,*ti2;
  718.  
  719.     tr1=table;
  720.     while (tr1->prev) tr1=tr1->prev;
  721.     while (tr1) {
  722.     ti1=tr1->first;
  723.     while (ti1) {
  724.         ti2=ti1->next;
  725.         if (ti1->contents) free(ti1->contents);
  726.         free(ti1);
  727.         ti1=ti2;
  728.     }
  729.     tr2=tr1;
  730.     tr1=tr1->next;
  731.     free(tr2);
  732.     }
  733. }
  734.  
  735. char *scan_expression(char *c, int *result);
  736.  
  737. static char *scan_format(char *c, TABLEROW **result, int *maxcol)
  738. {
  739.     TABLEROW *layout, *currow;
  740.     TABLEITEM *curfield;
  741.     int i,j;
  742.     if (*result) {
  743.     clear_table(*result);
  744.     }
  745.     layout= currow=(TABLEROW*) xmalloc(sizeof(TABLEROW));
  746.     currow->next=currow->prev=NULL;
  747.     currow->first=curfield=(TABLEITEM*) xmalloc(sizeof(TABLEITEM));
  748.     *curfield=emptyfield;
  749.     while (*c && *c!='.') {
  750.     switch (*c) {
  751.     case 'C': case 'c': case 'N': case 'n':
  752.     case 'R': case 'r': case 'A': case 'a':
  753.     case 'L': case 'l': case 'S': case 's':
  754.     case '^': case '_':
  755.         if (curfield->align) {
  756.         curfield->next=(TABLEITEM*)xmalloc(sizeof(TABLEITEM));
  757.         curfield=curfield->next;
  758.         *curfield=emptyfield;
  759.         }
  760.         curfield->align=toupper(*c);
  761.         c++;
  762.         break;
  763.     case 'i': case 'I': case 'B': case 'b':
  764.         curfield->font = toupper(*c);
  765.         c++;
  766.         break;
  767.     case 'f': case 'F':
  768.         c++;
  769.         curfield->font = toupper(*c);
  770.         c++;
  771.         if (!isspace(*c)) c++;
  772.         break;
  773.     case 't': case 'T': curfield->valign='t'; c++; break;
  774.     case 'p': case 'P':
  775.         c++;
  776.         i=j=0;
  777.         if (*c=='+') { j=1; c++; }
  778.         if (*c=='-') { j=-1; c++; }
  779.         while (isdigit(*c)) i=i*10+(*c++)-'0';
  780.         if (j) curfield->size= i*j; else curfield->size=j-10;
  781.         break;
  782.     case 'v': case 'V':
  783.     case 'w': case 'W':
  784. //        c=scan_expression(c+2,&curfield->width);
  785.              c++;
  786.          if (*c == '(') {
  787.             c=scan_expression(c+1,&curfield->width);
  788.          } else {
  789.              i=0;
  790.              while (isdigit(*c)) i=i*10+(*c++)-'0';
  791.             curfield->width=i;
  792.          }
  793.         break;
  794.     case '|':
  795.         if (curfield->align) curfield->vleft++;
  796.         else curfield->vright++;
  797.         c++;
  798.         break;
  799.     case 'e': case 'E':
  800.         c++;
  801.         break;
  802.     case '0': case '1': case '2': case '3': case '4':
  803.     case '5': case '6': case '7': case '8': case '9':
  804.         i=0;
  805.         while (isdigit(*c)) i=i*10+(*c++)-'0';
  806.         curfield->space=i;
  807.         break;
  808.     case ',': case '\n':
  809.         currow->next=(TABLEROW*)xmalloc(sizeof(TABLEROW));
  810.         currow->next->prev=currow;
  811.         currow=currow->next;
  812.         currow->next=NULL;
  813.         curfield=currow->first=(TABLEITEM*)xmalloc(sizeof(TABLEITEM));
  814.         *curfield=emptyfield;
  815.         c++;
  816.         break;
  817.     default:
  818.         c++;
  819.         break;
  820.     }
  821.     }
  822.     if (*c=='.') while (*c++!='\n');
  823.     *maxcol=0;
  824.     currow=layout;
  825.     while (currow) {
  826.     curfield=layout->first;
  827.     i=0;
  828.     while (curfield) {
  829.         i++;
  830.         curfield=curfield->next;
  831.     }
  832.     if (i>*maxcol) *maxcol=i;
  833.     currow=currow->next;
  834.     }
  835.     *result=layout;
  836.     return c;
  837. }
  838.  
  839. static TABLEROW *
  840. next_row(TABLEROW *tr)
  841. {
  842.     if (tr->next) {
  843.     tr=tr->next;
  844.     if (!tr->next) next_row(tr);
  845.     return tr;
  846.     } else {
  847.     TABLEITEM *ti, *ti2;
  848.     tr->next=(TABLEROW*)xmalloc(sizeof(TABLEROW));
  849.     tr->next->prev=tr;
  850.     ti=tr->first;
  851.     tr=tr->next;
  852.     tr->next=NULL;
  853.     if (ti) tr->first=ti2=(TABLEITEM*) xmalloc(sizeof(TABLEITEM));
  854.     else tr->first=ti2=NULL;
  855.     while (ti!=ti2) {
  856.         *ti2=*ti;
  857.         ti2->contents=NULL;
  858.         if ((ti=ti->next)) {
  859.         ti2->next=(TABLEITEM*) xmalloc(sizeof(TABLEITEM));
  860.         }
  861.         ti2=ti2->next;
  862.     }
  863.     return tr;
  864.     }
  865. }
  866.  
  867. char itemreset[20]="\\fR\\s0";
  868.  
  869. static char *
  870. scan_table(char *c) {
  871.     char *h;
  872.     char *g;
  873.     int center=0, expand=0, box=0, border=0, linesize=1;
  874.     int i,j,maxcol=0, finished=0;
  875.     int oldfont, oldsize,oldfillout;
  876.     char itemsep='\t';
  877.     TABLEROW *layout=NULL, *currow;
  878.     TABLEITEM *curfield;
  879.     while (*c++!='\n');        /* skip TS */
  880.     h=c;
  881.     if (*h=='.') return c-1;
  882.     oldfont=current_font;
  883.     oldsize=current_size;
  884.     oldfillout=fillout;
  885.     out_html(change_to_font(0));
  886.     out_html(change_to_size(0));
  887.     if (!fillout) {
  888.     fillout=1;
  889.     out_html("</PRE>");
  890.     }
  891.     while (*h && *h!='\n') h++;
  892.     if (h[-1]==';') {
  893.     /* scan table options */
  894.     while (c<h) {
  895.         while (isspace(*c)) c++;
  896.         for (i=0; tableopt[i] && strncmp(tableopt[i],c,tableoptl[i]);i++);
  897.         c=c+tableoptl[i];
  898.         switch (i) {
  899.         case 0: center=1; break;
  900.         case 1: expand=1; break;
  901.         case 2: box=1; break;
  902.         case 3: border=1; break;
  903.         case 4: box=2; break;
  904.         case 5: while (*c++!='('); itemsep=*c++; break;
  905.         case 6: while (*c++!='('); linesize=0;
  906.         while (isdigit(*c)) linesize=linesize*10+(*c++)-'0';
  907.         break;
  908.         case 7: while (*c!=')') c++;
  909.         default: break;
  910.         }
  911.         c++;
  912.     }
  913.     c=h+1;
  914.     }
  915.     /* scan layout */
  916.     c=scan_format(c,&layout, &maxcol);
  917.     currow=layout;
  918.     next_row(currow);
  919.     curfield=layout->first;
  920.     i=0;
  921.     while (!finished && *c) {
  922.     /* search item */
  923.     h=c;
  924.     if ((*c=='_' || *c=='=') && (c[1]==itemsep || c[1]=='\n')) {
  925.         if (c[-1]=='\n' && c[1]=='\n') {
  926.         if (currow->prev) {
  927.             currow->prev->next=(TABLEROW*) xmalloc(sizeof(TABLEROW));
  928.             currow->prev->next->next=currow;
  929.             currow->prev->next->prev=currow->prev;
  930.             currow->prev=currow->prev->next;
  931.         } else {
  932.             currow->prev=layout=(TABLEROW*) xmalloc(sizeof(TABLEROW));
  933.             currow->prev->prev=NULL;
  934.             currow->prev->next=currow;
  935.         }
  936.         curfield=currow->prev->first=
  937.             (TABLEITEM*) xmalloc(sizeof(TABLEITEM));
  938.         *curfield=emptyfield;
  939.         curfield->align=*c;
  940.         curfield->colspan=maxcol;
  941.         curfield=currow->first;
  942.         c=c+2;
  943.         } else {
  944.         if (curfield) {
  945.             curfield->align=*c;
  946.             do {
  947.             curfield=curfield->next;
  948.             } while (curfield && curfield->align=='S');
  949.         }
  950.         if (c[1]=='\n') {
  951.             currow=next_row(currow);
  952.             curfield=currow->first;
  953.         }
  954.         c=c+2;
  955.         }
  956.     } else if (*c=='T' && c[1]=='{') {
  957.         h=c+2;
  958.         c=strstr(h,"\nT}");
  959.         c++;
  960.         *c=0;
  961.         g=NULL;
  962.         scan_troff(h, 0, &g);
  963.         scan_troff(itemreset, 0, &g);
  964.         *c='T';
  965.         c+=3;
  966.         if (curfield) {
  967.         curfield->contents=g;
  968.         do {
  969.             curfield=curfield->next;
  970.         } while (curfield && curfield->align=='S');
  971.         } else
  972.         if (g) free(g);
  973.         if (c[-1]=='\n') {
  974.         currow=next_row(currow);
  975.         curfield=currow->first;
  976.         }
  977.     } else if (*c=='.' && c[1]=='T' && c[2]=='&' && c[-1]=='\n') {
  978.         TABLEROW *hr;
  979.         while (*c++!='\n');
  980.         hr=currow;
  981.         currow=currow->prev;
  982.         hr->prev=NULL;
  983.         c=scan_format(c,&hr, &i);
  984.         hr->prev=currow;
  985.         currow->next=hr;
  986.         currow=hr;
  987.         next_row(currow);
  988.         curfield=currow->first;
  989.     } else if (*c=='.' && c[1]=='T' && c[2]=='E' && c[-1]=='\n') {
  990.         finished=1;
  991.         while (*c++!='\n');
  992.         if (currow->prev)
  993.         currow->prev->next=NULL;
  994.         currow->prev=NULL;
  995.         clear_table(currow);
  996.     } else if (*c=='.' && c[-1]=='\n' && !isdigit(c[1])) {
  997.         /* skip troff request inside table (usually only .sp ) */
  998.         while (*c++!='\n');
  999.     } else {
  1000.         h=c;
  1001.         while (*c && (*c!=itemsep || c[-1]=='\\') &&
  1002.            (*c!='\n' || c[-1]=='\\')) c++;
  1003.         i=0;
  1004.         if (*c==itemsep) {i=1; *c='\n'; }
  1005.         if (h[0]=='\\' && h[2]=='\n' &&
  1006.         (h[1]=='_' || h[1]=='^')) {
  1007.         if (curfield) {
  1008.             curfield->align=h[1];
  1009.             do {
  1010.             curfield=curfield->next;
  1011.             } while (curfield && curfield->align=='S');
  1012.         }
  1013.         h=h+3;
  1014.         } else {
  1015.         g=NULL;
  1016.         h=scan_troff(h,1,&g);
  1017.         scan_troff(itemreset,0,&g);
  1018.         if (curfield) {
  1019.             curfield->contents=g;
  1020.             do {
  1021.             curfield=curfield->next;
  1022.             } while (curfield && curfield->align=='S');
  1023.         } else if (g) free(g);
  1024.         }
  1025.         if (i) *c=itemsep;
  1026.         c=h;
  1027.         if (c[-1]=='\n') {
  1028.         currow=next_row(currow);
  1029.         curfield=currow->first;
  1030.         }
  1031.     }
  1032.     }
  1033.     /* calculate colspan and rowspan */
  1034. #if 0
  1035.     currow=layout;
  1036.     while (currow->next) currow=currow->next;
  1037.     while (currow) {
  1038.     TABLEITEM *ti, *ti1=NULL, *ti2=NULL;
  1039.     ti=currow->first;
  1040.     if (currow->prev) ti1=currow->prev->first;
  1041.     while (ti) {
  1042.         switch (ti->align) {
  1043.         case 'S':
  1044.         if (ti2) {
  1045.             ti2->colspan++;
  1046.             if (ti2->rowspan<ti->rowspan) ti2->rowspan=ti->rowspan;
  1047.         }
  1048.         break;
  1049.         case '^':
  1050.         if (ti1) ti1->rowspan++;
  1051.         default:
  1052.         if (!ti2) ti2=ti;
  1053.         else {
  1054.             do {
  1055.             ti2=ti2->next;
  1056.             } while (ti2 && curfield->align=='S');
  1057.         }
  1058.         break;
  1059.         }
  1060.         ti=ti->next;
  1061.         if (ti1) ti1=ti1->next;
  1062.     }
  1063.     currow=currow->prev;
  1064.     }
  1065. #endif
  1066.     /* produce html output */
  1067.     if (center) out_html("<CENTER>");
  1068.     if (box==2) out_html("<TABLE BORDER><TR><TD>");
  1069.     out_html("<TABLE");
  1070.     if (box || border) {
  1071.     out_html(" BORDER");
  1072.     if (!border) out_html("><TR><TD><TABLE");
  1073.     if (expand) out_html(" WIDTH=100%");
  1074.     }
  1075.     out_html(">\n");
  1076.     currow=layout;
  1077.     while (currow) {
  1078.     j=0;
  1079.     out_html("<TR VALIGN=top>");
  1080.     curfield=currow->first;
  1081.     while (curfield) {
  1082.         if (curfield->align!='S' && curfield->align!='^') {
  1083.         out_html("<TD");
  1084.         switch (curfield->align) {
  1085.         case 'N':
  1086.             curfield->space+=4;
  1087.         case 'R':
  1088.             out_html(" ALIGN=right");
  1089.             break;
  1090.         case 'C':
  1091.             out_html(" ALIGN=center");
  1092.         default:
  1093.             break;
  1094.         }
  1095.         if (!curfield->valign && curfield->rowspan>1)
  1096.             out_html(" VALIGN=center");
  1097.         if (curfield->colspan>1) {
  1098.             char buf[5];
  1099.             out_html(" COLSPAN=");
  1100.             sprintf(buf, "%i", curfield->colspan);
  1101.             out_html(buf);
  1102.         }
  1103.         if (curfield->rowspan>1) {
  1104.             char buf[5];
  1105.             out_html(" ROWSPAN=");
  1106.             sprintf(buf, "%i", curfield->rowspan);
  1107.             out_html(buf);
  1108.         }
  1109.         j=j+curfield->colspan;
  1110.         out_html(">");
  1111.         if (curfield->size) out_html(change_to_size(curfield->size));
  1112.         if (curfield->font) out_html(change_to_font(curfield->font));
  1113.         switch (curfield->align) {
  1114.         case '=': out_html("<HR><HR>"); break;
  1115.         case '_': out_html("<HR>"); break;
  1116.         default:
  1117.             if (curfield->contents) out_html(curfield->contents);
  1118.             break;
  1119.         }
  1120.         if (curfield->space)
  1121.             for (i=0; i<curfield->space;i++) out_html("&nbsp;");
  1122.         if (curfield->font) out_html(change_to_font(0));
  1123.         if (curfield->size) out_html(change_to_size(0));
  1124.         if (j>=maxcol && curfield->align>'@' && curfield->align!='_')
  1125.             out_html("<BR>");
  1126.         out_html("</TD>");
  1127.         }
  1128.         curfield=curfield->next;
  1129.     }
  1130.     out_html("</TR>\n");
  1131.     currow=currow->next;
  1132.     }
  1133.     if (box && !border) out_html("</TABLE>");
  1134.     out_html("</TABLE>");
  1135.     if (box==2) out_html("</TABLE>");
  1136.     if (center) out_html("</CENTER>\n");
  1137.     else out_html("\n");
  1138.     if (!oldfillout) out_html("<PRE>");
  1139.     fillout=oldfillout;
  1140.     out_html(change_to_size(oldsize));
  1141.     out_html(change_to_font(oldfont));
  1142.     return c;
  1143. }
  1144.  
  1145. char *scan_expression(char *c, int *result) {
  1146.     int value=0,value2,sign=1,opex=0;
  1147.     char oper='c';
  1148.  
  1149.     if (*c=='!') {
  1150.     c=scan_expression(c+1, &value);
  1151.     value= (!value);
  1152.     } else if (*c=='n') {
  1153.     c++;
  1154.     value=nroff;
  1155.     } else if (*c=='t') {
  1156.     c++;
  1157.     value=1-nroff;
  1158.     } else if (*c=='\'' || *c=='"' || *c<' ' || (*c=='\\' && c[1]=='(')) {
  1159.     /* ?string1?string2?
  1160.     ** test if string1 equals string2.
  1161.     */
  1162.     char *st1=NULL, *st2=NULL, *h;
  1163.     char *tcmp=NULL;
  1164.     char sep;
  1165.     sep=*c;
  1166.     if (sep=='\\') {
  1167.         tcmp=c;
  1168.         c=c+3;
  1169.     }
  1170.     c++;
  1171.     h=c;
  1172.     while (*c!= sep && (!tcmp || strncmp(c,tcmp,4))) c++;
  1173.     *c='\n';
  1174.     scan_troff(h, 1, &st1);
  1175.     *c=sep;
  1176.     if (tcmp) c=c+3;
  1177.     c++;
  1178.     h=c;
  1179.     while (*c!=sep && (!tcmp || strncmp(c,tcmp,4))) c++;
  1180.     *c='\n';
  1181.     scan_troff(h,1,&st2);
  1182.     *c=sep;
  1183.     if (!st1 && !st2) value=1;
  1184.     else if (!st1 || !st2) value=0;
  1185.     else value=(!strcmp(st1, st2));
  1186.     if (st1) free(st1);
  1187.     if (st2) free(st2);
  1188.     if (tcmp) c=c+3;
  1189.     c++;
  1190.     } else {
  1191.     while (*c && !isspace(*c) && *c!=')') {
  1192.         opex=0;
  1193.         switch (*c) {
  1194.         case '(':
  1195.         c=scan_expression(c+1, &value2);
  1196.         value2=sign*value2;
  1197.         opex=1;
  1198.         break;
  1199.         case '.':
  1200.         case '0': case '1':
  1201.         case '2': case '3':
  1202.         case '4': case '5':
  1203.         case '6': case '7':
  1204.         case '8': case '9': {
  1205.         int num=0,denum=1;
  1206.         value2=0;
  1207.         while (isdigit(*c)) value2=value2*10+((*c++)-'0');
  1208.         if (*c=='.') {
  1209.             c++;
  1210.             while (isdigit(*c)) {
  1211.             num=num*10+((*c++)-'0');
  1212.             denum=denum*10;
  1213.             }
  1214.         }
  1215.         if (isalpha(*c)) {
  1216.             /* scale indicator */
  1217.             switch (*c) {
  1218.             case 'i': /* inch -> 10pt */
  1219.             value2=value2*10+(num*10+denum/2)/denum;
  1220.             num=0;
  1221.             break;
  1222.             default:
  1223.             break;
  1224.             }
  1225.             c++;
  1226.         }
  1227.         value2=value2+(num+denum/2)/denum;
  1228.         value2=sign*value2;
  1229.         opex=1;
  1230.         break;
  1231.         }
  1232.         case '\\':
  1233.         c=scan_escape(c+1);
  1234.         value2=intresult*sign;
  1235.         if (isalpha(*c)) c++; /* scale indicator */
  1236.         opex=1;
  1237.         break;
  1238.         case '-':
  1239.         if (oper) { sign=-1; c++; break; }
  1240.         case '>':
  1241.         case '<':
  1242.         case '+':
  1243.         case '/':
  1244.         case '*':
  1245.         case '%':
  1246.         case '&':
  1247.         case '=':
  1248.         case ':':
  1249.         if (c[1]=='=') oper=(*c++) +16; else oper=*c;
  1250.         c++;
  1251.         break;
  1252.         default: c++; break;
  1253.         }
  1254.         if (opex) {
  1255.         sign=1;
  1256.         switch (oper) {
  1257.         case 'c': value=value2; break;
  1258.         case '-': value=value-value2; break;
  1259.         case '+': value=value+value2; break;
  1260.         case '*': value=value*value2; break;
  1261.         case '/': if (value2) value=value/value2; break;
  1262.         case '%': if (value2) value=value%value2; break;
  1263.         case '<': value=(value<value2); break;
  1264.         case '>': value=(value>value2); break;
  1265.         case '>'+16: value=(value>=value2); break;
  1266.         case '<'+16: value=(value<=value2); break;
  1267.         case '=': case '='+16: value=(value==value2); break;
  1268.         case '&': value = (value && value2); break;
  1269.         case ':': value = (value || value2); break;
  1270.         default: fprintf(stderr,
  1271.                  "man2html: Unknown operator %c.\n", oper);
  1272.         }
  1273.         oper=0;
  1274.         }
  1275.     }
  1276.     if (*c==')') c++;
  1277.     }
  1278.     *result=value;
  1279.     return c;
  1280. }
  1281.  
  1282. static void
  1283. trans_char(char *c, char s, char t) {
  1284.     char *sl = c;
  1285.     int slash = 0;
  1286.  
  1287.     while (*sl && (*sl != '\n' || slash)) {
  1288.         if (!slash) {
  1289.             if (*sl == escapesym)
  1290.                 slash = 1;
  1291.             else if (*sl == s)
  1292.                 *sl = t;
  1293.         } else
  1294.             slash = 0;
  1295.         sl++;
  1296.     }
  1297. }
  1298.  
  1299. /*
  1300.  * Read STR until end-of-line (not preceded by \).
  1301.  * Find whitespace separated words, and store starts in WORDS of lth MAXN.
  1302.  * Return number of words in N.
  1303.  * Replace each end-of-word by the character EOW (usually \n or 0).
  1304.  * Return pointer to last char seen (either \n or 0).
  1305.  *
  1306.  * A part \"... is skipped.
  1307.  * Quotes not preceded by \ are replaced by \a.
  1308.  */
  1309. static char *
  1310. fill_words(char *str, char *words[], int maxn, int *n, char eow) {
  1311.     char *s = str;
  1312.     int backslash = 0;
  1313.     int skipspace = 0;    /* 1 if space is not end-of-word */
  1314.  
  1315.     *n = 0;
  1316.     words[*n] = s;
  1317.     while (*s && (*s != '\n' || backslash)) {
  1318.         if (!backslash) {
  1319.             if (*s == '"') {
  1320.                 *s = '\a';
  1321.                 skipspace = !skipspace;
  1322.             } else if (*s == escapesym) {
  1323.                 backslash = 1;
  1324.             } else if ((*s == ' ' || *s == '\t') && !skipspace) {
  1325.                 *s = eow;
  1326.                 if (words[*n] != s && *n < maxn-1)
  1327.                     (*n)++;
  1328.                 words[*n] = s+1;
  1329.             }
  1330.         } else {
  1331.             if (*s == '"') {
  1332.                 s--;
  1333.                 *s = eow;
  1334.                 if (words[*n] != s && *n < maxn-1)
  1335.                     (*n)++;
  1336.                 s++;
  1337.                 while (*s && *s != '\n') s++;
  1338.                 words[*n] = s;
  1339.                 s--;
  1340.             }
  1341.             backslash = 0;
  1342.         }
  1343.         s++;
  1344.     }
  1345.     if (s != words[*n])
  1346.         (*n)++;
  1347.     return s;
  1348. }
  1349.  
  1350.  
  1351. char *section_list[] = {
  1352.     "1", "User Commands ",
  1353.     "1C", "User Commands",
  1354.     "1G", "User Commands",
  1355.     "1S", "User Commands",
  1356.     "1V", "User Commands ",
  1357.     "2", "System Calls",
  1358.     "2V", "System Calls",
  1359.     "3", "C Library Functions",
  1360.     "3C", "Compatibility Functions",
  1361.     "3F", "Fortran Library Routines",
  1362.     "3K", "Kernel VM Library Functions",
  1363.     "3L", "Lightweight Processes Library",
  1364.     "3M", "Mathematical Library",
  1365.     "3N", "Network Functions",
  1366.     "3R", "RPC Services Library",
  1367.     "3S", "Standard I/O Functions",
  1368.     "3V", "C Library Functions",
  1369.     "3X", "Miscellaneous Library Functions",
  1370.     "4", "Devices and Network Interfaces",
  1371.     "4F", "Protocol Families",
  1372.     "4I", "Devices and Network Interfaces",
  1373.     "4M", "Devices and Network Interfaces",
  1374.     "4N", "Devices and Network Interfaces",
  1375.     "4P", "Protocols",
  1376.     "4S", "Devices and Network Interfaces",
  1377.     "4V", "Devices and Network Interfaces",
  1378.     "5", "File Formats",
  1379.     "5V", "File Formats",
  1380.     "6", "Games and Demos",
  1381.     "7", "Environments, Tables, and Troff Macros",
  1382.     "7V", "Environments, Tables, and Troff Macros",
  1383.     "8", "Maintenance Commands",
  1384.     "8C", "Maintenance Commands",
  1385.     "8S", "Maintenance Commands",
  1386.     "8V", "Maintenance Commands",
  1387.     "L", "Local Commands",
  1388. /* for Solaris:
  1389.     "1", "User Commands",
  1390.     "1B", "SunOS/BSD Compatibility Package Commands",
  1391.     "1b", "SunOS/BSD Compatibility Package Commands",
  1392.     "1C", "Communication Commands ",
  1393.     "1c", "Communication Commands",
  1394.     "1F", "FMLI Commands ",
  1395.     "1f", "FMLI Commands",
  1396.     "1G", "Graphics and CAD Commands ",
  1397.     "1g", "Graphics and CAD Commands ",
  1398.     "1M", "Maintenance Commands",
  1399.     "1m", "Maintenance Commands",
  1400.     "1S", "SunOS Specific Commands",
  1401.     "1s", "SunOS Specific Commands",
  1402.     "2", "System Calls",
  1403.     "3", "C Library Functions",
  1404.     "3B", "SunOS/BSD Compatibility Library Functions",
  1405.     "3b", "SunOS/BSD Compatibility Library Functions",
  1406.     "3C", "C Library Functions",
  1407.     "3c", "C Library Functions",
  1408.     "3E", "C Library Functions",
  1409.     "3e", "C Library Functions",
  1410.     "3F", "Fortran Library Routines",
  1411.     "3f", "Fortran Library Routines",
  1412.     "3G", "C Library Functions",
  1413.     "3g", "C Library Functions",
  1414.     "3I", "Wide Character Functions",
  1415.     "3i", "Wide Character Functions",
  1416.     "3K", "Kernel VM Library Functions",
  1417.     "3k", "Kernel VM Library Functions",
  1418.     "3L", "Lightweight Processes Library",
  1419.     "3l", "Lightweight Processes Library",
  1420.     "3M", "Mathematical Library",
  1421.     "3m", "Mathematical Library",
  1422.     "3N", "Network Functions",
  1423.     "3n", "Network Functions",
  1424.     "3R", "Realtime Library",
  1425.     "3r", "Realtime Library",
  1426.     "3S", "Standard I/O Functions",
  1427.     "3s", "Standard I/O Functions",
  1428.     "3T", "Threads Library",
  1429.     "3t", "Threads Library",
  1430.     "3W", "C Library Functions",
  1431.     "3w", "C Library Functions",
  1432.     "3X", "Miscellaneous Library Functions",
  1433.     "3x", "Miscellaneous Library Functions",
  1434.     "4", "File Formats",
  1435.     "4B", "SunOS/BSD Compatibility Package File Formats",
  1436.     "4b", "SunOS/BSD Compatibility Package File Formats",
  1437.     "5", "Headers, Tables, and Macros",
  1438.     "6", "Games and Demos",
  1439.     "7", "Special Files",
  1440.     "7B", "SunOS/BSD Compatibility Special Files",
  1441.     "7b", "SunOS/BSD Compatibility Special Files",
  1442.     "8", "Maintenance Procedures",
  1443.     "8C", "Maintenance Procedures",
  1444.     "8c", "Maintenance Procedures",
  1445.     "8S", "Maintenance Procedures",
  1446.     "8s", "Maintenance Procedures",
  1447.     "9", "DDI and DKI",
  1448.     "9E", "DDI and DKI Driver Entry Points",
  1449.     "9e", "DDI and DKI Driver Entry Points",
  1450.     "9F", "DDI and DKI Kernel Functions",
  1451.     "9f", "DDI and DKI Kernel Functions",
  1452.     "9S", "DDI and DKI Data Structures",
  1453.     "9s", "DDI and DKI Data Structures",
  1454.     "L", "Local Commands",
  1455. */
  1456.     NULL, "Misc. Reference Manual Pages",
  1457.     NULL, NULL
  1458. };
  1459.  
  1460. static char *
  1461. section_name(char *c)
  1462. {
  1463.     int i=0;
  1464.  
  1465.     if (!c) return "";
  1466.     while (section_list[i] && strcmp(c,section_list[i])) i=i+2;
  1467.     if (section_list[i+1]) return section_list[i+1];
  1468.     else return c;
  1469. }
  1470.  
  1471. int manidxlen = 0;
  1472. char *manidx = NULL;
  1473. int subs = 0;
  1474. int mip = 0;    /* current offset in manidx[] */
  1475. char label[5]="lbAA";
  1476.  
  1477. static void
  1478. manidx_need(int m) {
  1479.     if (mip + m >= manidxlen) {
  1480.         manidxlen += 10000;
  1481.         manidx = xrealloc(manidx, manidxlen);
  1482.     }
  1483. }
  1484.  
  1485. static void
  1486. add_to_index(int level, char *item)
  1487. {
  1488.     char *c = NULL;
  1489.  
  1490.     label[3]++;
  1491.     if (label[3]>'Z') {
  1492.     label[3]='A';
  1493.     label[2]++;
  1494.     }
  1495.  
  1496.     if (level != subs) {
  1497.     manidx_need(6);
  1498.     if (subs) {
  1499.         strcpy(manidx+mip, "</DL>\n");
  1500.         mip += 6;
  1501.     } else {
  1502.         strcpy(manidx+mip, "<DL>\n");
  1503.         mip += 5;
  1504.     }
  1505.     }
  1506.     subs = level;
  1507.  
  1508.     scan_troff(item, 1, &c);
  1509.     manidx_need(100 + strlen(c));
  1510.     sprintf(manidx+mip, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label, c);
  1511.     if (c) free(c);
  1512.     while (manidx[mip]) mip++;
  1513. }
  1514.  
  1515. static char *
  1516. skip_till_newline(char *c)
  1517. {
  1518.     int lvl=0;
  1519.  
  1520.     while (*c && (*c!='\n' || lvl>0)) {
  1521.     if (*c=='\\') {
  1522.         c++;
  1523.         if (*c=='}') lvl--; else if (*c=='{') lvl++;
  1524.     }
  1525.     c++;
  1526.     }
  1527.     c++;
  1528.     if (lvl<0 && newline_for_fun) {
  1529.     newline_for_fun = newline_for_fun+lvl;
  1530.     if (newline_for_fun<0) newline_for_fun=0;
  1531.     }
  1532.     return c;
  1533. }
  1534.  
  1535. int ifelseval=0;
  1536.  
  1537. static char *
  1538. scan_request(char *c) {
  1539.                                   /* BSD Mandoc stuff - by Michael Hamilton */
  1540.     static int mandoc_synopsis=0; /* True if we are in the synopsis section */
  1541.     static int mandoc_command=0;  /* True if this is mandoc page */
  1542.     static int mandoc_bd_options; /* Only copes with non-nested Bd's */
  1543.     static int inXo=0;
  1544.  
  1545.     int i,j,mode = 0;
  1546.     char *h;
  1547.     char *wordlist[20];
  1548.     int words;
  1549.     char *sl;
  1550.     STRDEF *owndef;
  1551.  
  1552.     while (*c == ' ' || *c == '\t')
  1553.         c++;
  1554.     if (c[0] == '\n')
  1555.         return c+1;
  1556.     if (c[1] == '\n')
  1557.         j = 1;
  1558.     else
  1559.         j = 2;
  1560.     while (c[j] == ' ' || c[j] == '\t')
  1561.         j++;
  1562.     if (c[0] == escapesym) {
  1563.     /* some pages use .\" .\$1 .\} */
  1564.     /* .\$1 is too difficult/stupid */
  1565.     if (c[1] == '$')
  1566.         c = skip_till_newline(c);
  1567.     else
  1568.         c = scan_escape(c+1);
  1569.     } else {
  1570.     i=V(c[0],c[1]);
  1571.     switch (i) {
  1572.     case V('a','b'):
  1573.         h=c+j;
  1574.         while (*h && *h !='\n') h++;
  1575.         *h=0;
  1576.         if (scaninbuff && buffpos) {
  1577.         buffer[buffpos]=0;
  1578.         fprintf(out, "%s\n", buffer);
  1579.         }
  1580.         fprintf(stderr, "%s\n", c+2);        /* XXX */
  1581.         exit(0);
  1582.         break;
  1583.     case V('d','i'):
  1584.         {
  1585.         STRDEF *de;
  1586.         c=c+j;
  1587.         i=V(c[0],c[1]);
  1588.         if (*c == '\n') { c++;break; }
  1589.         while (*c && *c!='\n') c++;
  1590.         c++;
  1591.         h=c;
  1592.         while (*c && strncmp(c,".di",3)) while (*c && *c++!='\n');
  1593.         *c=0;
  1594.         de=strdef;
  1595.         while (de && de->nr !=i) de=de->next;
  1596.         if (!de) {
  1597.             de=(STRDEF*) xmalloc(sizeof(STRDEF));
  1598.             de->nr=i;
  1599.             de->slen=0;
  1600.             de->next=strdef;
  1601.             de->st=NULL;
  1602.             strdef=de;
  1603.         } else {
  1604.             if (de->st) free(de->st);
  1605.             de->slen=0;
  1606.             de->st=NULL;
  1607.         }
  1608.         scan_troff(h,0,&de->st);
  1609.         *c='.';
  1610.         while (*c && *c++!='\n');
  1611.         break;
  1612.         }
  1613.     case V('d','s'):
  1614.         mode=1;
  1615.     case V('a','s'):
  1616.         {
  1617.         STRDEF *de;
  1618.         int oldcurpos=curpos;
  1619.         c=c+j;
  1620.         while (*c == ' ') c++;
  1621.         i=V(c[0],c[1]);
  1622.         j=0;
  1623.         while (c[j] && c[j]!='\n') j++;
  1624.         if (j<3) { c=c+j; break; }
  1625.         if (c[1] == ' ') c=c+1; else c=c+2;
  1626.         while (isspace(*c)) c++;
  1627.         if (*c == '"') c++;
  1628.         de=strdef;
  1629.         while (de && de->nr != i) de=de->next;
  1630.         single_escape=1;
  1631.         curpos=0;
  1632.         if (!de) {
  1633.             char *h;
  1634.             de=(STRDEF*) xmalloc(sizeof(STRDEF));
  1635.             de->nr=i;
  1636.             de->slen=0;
  1637.             de->next=strdef;
  1638.             de->st=NULL;
  1639.             strdef=de;
  1640.             h=NULL;
  1641.             c=scan_troff(c, 1, &h);
  1642.             de->st=h;
  1643.             de->slen=curpos;
  1644.         } else {
  1645.             if (mode) {        /* .ds */
  1646.             char *h=NULL;
  1647.             c=scan_troff(c, 1, &h);
  1648.             free(de->st);    /* segfault XXX */
  1649.             de->slen=curpos;
  1650.             de->st=h;
  1651.             } else {        /* .as */
  1652.             c=scan_troff(c,1,&de->st);     /* XXX */
  1653.             de->slen+=curpos;
  1654.             }
  1655.         }
  1656.         single_escape=0;
  1657.         curpos=oldcurpos;
  1658.         }
  1659.         break;
  1660.     case V('b','r'):
  1661.         if (still_dd) out_html("<DD>");
  1662.         else out_html("<BR>\n");
  1663.         curpos=0;
  1664.         c=c+j;
  1665.         if (c[0] == escapesym) { c=scan_escape(c+1); }
  1666.         c=skip_till_newline(c);break;
  1667.     case V('c','2'):
  1668.         c=c+j;
  1669.         if (*c!='\n') { nobreaksym=*c; }
  1670.         else nobreaksym='\'';
  1671.         c=skip_till_newline(c);
  1672.         break;
  1673.     case V('c','c'):
  1674.         c=c+j;
  1675.         if (*c!='\n') { controlsym=*c; }
  1676.         else controlsym='.';
  1677.         c=skip_till_newline(c);
  1678.         break;
  1679.     case V('c','e'):
  1680.         c=c+j;
  1681.         if (*c == '\n') { i=1; }
  1682.         else {
  1683.         i=0;
  1684.         while ('0'<=*c && *c<='9') {
  1685.             i=i*10+*c-'0';
  1686.             c++;
  1687.         }
  1688.         }
  1689.         c=skip_till_newline(c);
  1690.         /* center next i lines */
  1691.         if (i>0) {
  1692.         out_html("<CENTER>\n");
  1693.         while (i && *c) {
  1694.             char *line=NULL;
  1695.             c=scan_troff(c,1, &line);
  1696.             if (line && strncmp(line, "<BR>", 4)) {
  1697.             out_html(line);
  1698.             out_html("<BR>\n");
  1699.             i--;
  1700.             }
  1701.         }
  1702.         out_html("</CENTER>\n");
  1703.         curpos=0;
  1704.         }
  1705.         break;
  1706.     case V('e','c'):
  1707.         c=c+j;
  1708.         if (*c!='\n') { escapesym=*c; }
  1709.         else escapesym='\\';
  1710.         break;
  1711.         c=skip_till_newline(c);
  1712.     case V('e','o'):
  1713.         escapesym=0;
  1714.         c=skip_till_newline(c);
  1715.         break;
  1716.     case V('e','x'):
  1717.         exit(0);
  1718.         break;
  1719.     case V('f','c'):
  1720.         c=c+j;
  1721.         if  (*c == '\n') {
  1722.         fieldsym=padsym=0;
  1723.         } else {
  1724.         fieldsym=c[0];
  1725.         padsym=c[1];
  1726.         }
  1727.         c=skip_till_newline(c);
  1728.         break;
  1729.     case V('f','i'):
  1730.         if (!fillout) {
  1731.         out_html(change_to_font(0));
  1732.         out_html(change_to_size('0'));
  1733.         out_html("</PRE>\n");
  1734.         }
  1735.         curpos=0;
  1736.         fillout=1;
  1737.         c=skip_till_newline(c);
  1738.         break;
  1739.     case V('f','t'):
  1740.         c=c+j;
  1741.         if (*c == '\n') {
  1742.         out_html(change_to_font(0));
  1743.         } else {
  1744.         if (*c == escapesym) {
  1745.             int fn;
  1746.             c=scan_expression(c, &fn);
  1747.             c--;
  1748.             out_html(change_to_font(fn));
  1749.         } else {
  1750.             out_html(change_to_font(*c));
  1751.             c++;
  1752.         }
  1753.         }
  1754.         c=skip_till_newline(c);
  1755.         break;
  1756.     case V('e','l'):
  1757.         /* .el anything : else part of if else */
  1758.         if (ifelseval) {
  1759.         c=c+j;
  1760.         c[-1]='\n';
  1761.         c=scan_troff(c,1,NULL);
  1762.         } else
  1763.         c=skip_till_newline(c+j);
  1764.         break;
  1765.     case V('i','e'):
  1766.         /* .ie c anything : then part of if else */
  1767.     case V('i','f'):
  1768.         /* .if c anything
  1769.          * .if !c anything
  1770.          * .if N anything
  1771.          * .if !N anything
  1772.          * .if 'string1'string2' anything
  1773.          * .if !'string1'string2' anything
  1774.          */
  1775.         c=c+j;
  1776.         c=scan_expression(c, &i);
  1777.         ifelseval=!i;
  1778.         if (i) {
  1779.         *c='\n';
  1780.         c++;
  1781.         c=scan_troff(c,1,NULL);
  1782.         } else
  1783.         c=skip_till_newline(c);
  1784.         break;
  1785.     case V('i','g'):    /* .ig: ignore until .. */
  1786.         {
  1787.         char *endwith="..\n";
  1788.         i=3;
  1789.         c=c+j;
  1790.         while (*c == ' ') c++;
  1791.         if (*c == escapesym && c[1] == '"')
  1792.             while (*c != '\n') c++;
  1793.         if (*c!='\n') {    /* .ig yy: ignore until .yy, then call .yy */
  1794.             endwith=c-1;i=1;
  1795.             c[-1]='.';
  1796.             while (*c && *c!='\n') c++,i++;
  1797.         }
  1798.         c++;
  1799.         while (*c && strncmp(c,endwith,i))
  1800.              while (*c && *c++!='\n');
  1801.         while (*c && *c++!='\n');
  1802.         break;
  1803.         }
  1804.     case V('n','f'):
  1805.         if (fillout) {
  1806.         out_html(change_to_font(0));
  1807.         out_html(change_to_size('0'));
  1808.         out_html("<PRE>\n");
  1809.         }
  1810.         curpos=0;
  1811.         fillout=0;
  1812.         c=skip_till_newline(c);
  1813.         break;
  1814.     case V('p','s'):
  1815.         c=c+j;
  1816.         if (*c == '\n') {
  1817.         out_html(change_to_size('0'));
  1818.         } else {
  1819.         j=0;i=0;
  1820.         if (*c == '-') { j= -1;c++; } else if (*c == '+') { j=1;c++;}
  1821.         c=scan_expression(c, &i);
  1822.         if (!j) { j=1; if (i>5) i=i-10; }
  1823.         out_html(change_to_size(i*j));
  1824.         }
  1825.         c=skip_till_newline(c);
  1826.         break;
  1827.     case V('s','p'):
  1828.         c=c+j;
  1829.         if (fillout) out_html("<P>"); else {
  1830.         out_html(NEWLINE);
  1831.         NEWLINE[0]='\n';
  1832.         }
  1833.         curpos=0;
  1834.         c=skip_till_newline(c);
  1835.         break;
  1836.     case V('s','o'):
  1837.         {
  1838.         FILE *f;
  1839.         int l; char *buf;
  1840.         char *name = NULL;
  1841.  
  1842.         curpos=0;
  1843.         c += j;            /* skip .so part and whitespace */
  1844.         if (*c == '/') {
  1845.             h = c;
  1846.         } else {        /* .so man3/cpow.3 -> ../man3/cpow.3 */
  1847.             h = c-3;
  1848.             h[0] = '.';
  1849.             h[1] = '.';
  1850.             h[2] = '/';
  1851.         }
  1852.         while (*c != '\n') c++;
  1853.         while (c[-1] == ' ') c--;
  1854.         while (*c != '\n') *c++ = 0;
  1855.         *c = 0;
  1856.         scan_troff(h,1, &name);
  1857.         if (name[3] == '/') h=name+3; else h=name;
  1858.         l = 0;
  1859. #ifdef _KOLIBRI
  1860.         ksys_bdfe_t bdfe;
  1861.         _ksys_file_get_info(h, &bdfe);
  1862.         l = bdfe.size;
  1863. #else
  1864.         struct stat stbuf;
  1865.         if (stat(h, &stbuf)!=-1) l=stbuf.st_size;
  1866. #endif
  1867.  
  1868.         buf = (char*) xmalloc((l+4)*sizeof(char));
  1869. #if NOCGI
  1870.                 if (!out_length) {
  1871.             char *t,*s;
  1872.             t=strrchr(fname, '/');
  1873.             if (!t) t=fname;
  1874.             //fprintf(stderr, "ln -s %s.html %s.html\n", h, t);
  1875.             s=strrchr(t, '.');if (!s) s=t;
  1876.             fprintf(out,"<HTML><HEAD><TITLE> Manpage of %s</TITLE>\n"
  1877.                "</HEAD><BODY>\n"
  1878.                "See the manpage for <A HREF=\"%s.html\">%s</A>.\n"
  1879.                "</BODY></HTML>\n",
  1880.                s, h, h);
  1881.         } else
  1882. #endif
  1883.                 {
  1884.             /* this works alright, except for section 3 */
  1885.             if (!l || !(f = fopen(h,"r"))) {
  1886.              fprintf(stderr,
  1887.                 "man2html: unable to open or read file %s\n", h);
  1888.              out_html("<BLOCKQUOTE>"
  1889.                   "man2html: unable to open or read file\n");
  1890.              out_html(h);
  1891.              out_html("</BLOCKQUOTE>\n");
  1892.             } else {
  1893.             i=fread(buf+1,1,l,f);
  1894.             fclose(f);
  1895.             buf[0]=buf[l]='\n';
  1896.             buf[l+1]=buf[l+2]=0;
  1897.             scan_troff(buf+1,0,NULL);
  1898.             }
  1899.             if (buf) free(buf);
  1900.         }
  1901.         *c++='\n';
  1902.         break;
  1903.         }
  1904.     case V('t','a'):
  1905.         c=c+j;
  1906.         j=0;
  1907.         while (*c!='\n') {
  1908.         sl=scan_expression(c, &tabstops[j]);
  1909.         if (*c == '-' || *c == '+') tabstops[j]+=tabstops[j-1];
  1910.         c=sl;
  1911.         while (*c == ' ' || *c == '\t') c++;
  1912.         if (j+1 < SIZE(tabstops))
  1913.             j++;
  1914.         }
  1915.         maxtstop=j;
  1916.         curpos=0;
  1917.         break;
  1918.     case V('t','i'):
  1919. #if 0
  1920.         dl_down();
  1921. #endif
  1922.         out_html("<BR>\n");
  1923.         c=c+j;
  1924.         c=scan_expression(c, &j);
  1925.         for (i=0; i<j; i++) out_html("&nbsp;");
  1926.         curpos=j;
  1927.         c=skip_till_newline(c);
  1928.         break;
  1929.     case V('t','m'):
  1930.         c=c+j;
  1931.         h=c;
  1932.         while (*c!='\n') c++;
  1933.         *c=0;
  1934.         fprintf(stderr,"%s\n", h);        /* XXX */
  1935.         *c='\n';
  1936.         break;
  1937.     case V('B',' '):
  1938.     case V('B','\n'):
  1939.     case V('I',' '):
  1940.     case V('I','\n'):
  1941.             /* parse one line in a certain font */
  1942.         out_html(change_to_font(*c));
  1943.         trans_char(c, '"', '\a');
  1944.         c=c+j;
  1945.         if (*c == '\n') c++;
  1946.         c=scan_troff(c, 1, NULL);
  1947.         out_html(change_to_font('R'));
  1948.         out_html(NEWLINE);
  1949.         if (fillout) curpos++; else curpos=0;
  1950.         break;
  1951.     case V('O','P'):  /* groff manpages use this construction */
  1952.             /* .OP a b : [ <B>a</B> <I>b</I> ] */
  1953.         mode=1;
  1954.         c[0]='B'; c[1]='I';
  1955.         out_html(change_to_font('R'));
  1956.         out_html("[");
  1957.         curpos++;
  1958.     case V('B','R'):
  1959.     case V('B','I'):
  1960.     case V('I','B'):
  1961.     case V('I','R'):
  1962.     case V('R','B'):
  1963.     case V('R','I'):
  1964.         {
  1965.         char font[2];
  1966.         font[0] = c[0]; font[1] = c[1];
  1967.         c = c+j;
  1968.         if (*c == '\n') c++;
  1969.         sl = fill_words(c, wordlist, SIZE(wordlist), &words, '\n');
  1970.         c = sl+1;
  1971.         /* .BR name (section)
  1972.         ** indicates a link. It will be added in the output routine.
  1973.         */
  1974.         for (i=0; i<words; i++) {
  1975.             if (mode) { out_html(" "); curpos++; }
  1976.             wordlist[i][-1]=' ';
  1977.             out_html(change_to_font(font[i&1]));
  1978.             scan_troff(wordlist[i],1,NULL);
  1979.         }
  1980.         out_html(change_to_font('R'));
  1981.         if (mode) { out_html(" ]"); curpos++;}
  1982.         out_html(NEWLINE); if (!fillout) curpos=0; else curpos++;
  1983.         }
  1984.         break;
  1985.     case V('D','T'):
  1986.         maxtstop = SIZE(tabstops);
  1987.         for (j=0; j<maxtstop; j++)
  1988.         tabstops[j]=(j+1)*8;
  1989.         c=skip_till_newline(c); break;
  1990.     case V('I','P'):
  1991.         sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
  1992.         c = sl+1;
  1993.         dl_begin();
  1994.             if (words) {
  1995.         scan_troff(wordlist[0], 1,NULL);
  1996.         }
  1997.         out_html("<DD>");
  1998.         curpos = 0;
  1999.         break;
  2000.     case V('T','P'):
  2001.         dl_begin();
  2002.         c=skip_till_newline(c);
  2003.         /* somewhere a definition ends with '.TP' */
  2004.         if (!*c) still_dd=1; else {
  2005.         c=scan_troff(c,1,NULL);
  2006.         out_html("<DD>");
  2007.         }
  2008.         curpos=0;
  2009.         break;
  2010.     case V('I','X'):
  2011.             /* general index */
  2012.         sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
  2013.         c = sl+1;
  2014.         j = 4;
  2015.         while (idxlabel[j] == 'Z') idxlabel[j--]='A';
  2016.         idxlabel[j]++;
  2017. #ifdef MAKEINDEX
  2018.         if (idxfile) {
  2019.          fprintf(idxfile, "%s@%s@", fname, idxlabel);
  2020.          for (j=0; j<words; j++) {
  2021.               h=NULL;
  2022.               scan_troff(wordlist[j], 1, &h);
  2023.               fprintf(idxfile, "_\b@%s", h);
  2024.               free(h);
  2025.          }
  2026.          fprintf(idxfile,"\n");
  2027.         }
  2028. #endif
  2029.             out_html("<A NAME=\"");
  2030.         out_html(idxlabel);
  2031.         /* this will not work in mosaic (due to a bug).
  2032.         ** Adding '&nbsp;' between '>' and '<' solves it, but creates
  2033.         ** some space. A normal space does not work.
  2034.         */
  2035.         out_html("\"></A>");
  2036.         break;
  2037.     case V('L','P'):
  2038.     case V('P','P'):
  2039.         dl_end();
  2040.         if (fillout) out_html("<P>\n"); else {
  2041.         out_html(NEWLINE);
  2042.         NEWLINE[0]='\n';
  2043.         }
  2044.         curpos=0;
  2045.         c=skip_till_newline(c);
  2046.         break;
  2047.     case V('H','P'):
  2048.         dl_begin();
  2049.         still_dd=1;
  2050.         c=skip_till_newline(c);
  2051.         curpos=0;
  2052.         break;
  2053.     case V('P','D'):
  2054.          c=skip_till_newline(c);
  2055.          break;
  2056.     case V('R','s'):        /* BSD mandoc */
  2057.     case V('R','S'):
  2058.         sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
  2059.         j = 1;
  2060.         if (words>0) scan_expression(wordlist[0], &j);
  2061.         if (j>=0) {
  2062.         dl_newlevel();
  2063.         c=skip_till_newline(c);
  2064.         curpos=0;
  2065.         break;
  2066.         }
  2067.     case V('R','e'):        /* BSD mandoc */
  2068.     case V('R','E'):
  2069.         dl_endlevel();
  2070.         c=skip_till_newline(c);
  2071.         curpos=0;
  2072.         break;
  2073.     case V('S','B'):
  2074.         out_html(change_to_size(-1));
  2075.         out_html(change_to_font('B'));
  2076.         c=scan_troff(c+j, 1, NULL);
  2077.         out_html(change_to_font('R'));
  2078.         out_html(change_to_size('0'));
  2079.         break;
  2080.     case V('S','M'):
  2081.         c=c+j;
  2082.         if (*c == '\n') c++;
  2083.         out_html(change_to_size(-1));
  2084.         trans_char(c,'"','\a');
  2085.         c=scan_troff(c,1,NULL);
  2086.         out_html(change_to_size('0'));
  2087.         break;
  2088.     case V('S','s'):        /* BSD mandoc */
  2089.         mandoc_command = 1;
  2090.     case V('S','S'):
  2091.         mode=1;
  2092.         goto sh_below;
  2093.     case V('S','h'):        /* BSD mandoc */
  2094.         mandoc_command = 1;
  2095.     case V('S','H'):
  2096.     sh_below:
  2097.         c=c+j;
  2098.         if (*c == '\n') c++;
  2099.         dl_down();
  2100.         out_html(change_to_font(0));
  2101.         out_html(change_to_size(0));
  2102.         if (!fillout) {
  2103.         fillout=1;
  2104.         out_html("</PRE>");
  2105.         }
  2106.         trans_char(c,'"', '\a');
  2107.         add_to_index(mode, c);
  2108.         out_html("<A NAME=\"");
  2109.         out_html(label);
  2110.         /* &nbsp; for mosaic users */
  2111.         if (mode) out_html("\">&nbsp;</A>\n<H3>");
  2112.         else out_html("\">&nbsp;</A>\n<H2>");
  2113.         mandoc_synopsis = (strncmp(c, "SYNOPSIS", 8) == 0);
  2114.         c = (mandoc_command ? scan_troff_mandoc : scan_troff)(c,1,NULL);
  2115.         if (mode) out_html("</H3>\n");
  2116.         else out_html("</H2>\n");
  2117.         curpos=0;
  2118.         break;
  2119.     case V('T','S'):
  2120.         c=scan_table(c);
  2121.         break;
  2122.     case V('D','t'):        /* BSD mandoc */
  2123.         mandoc_command = 1;
  2124.     case V('T','H'):
  2125.         if (!output_possible) {
  2126.         sl = fill_words(c+j, wordlist, SIZE(wordlist), &words, 0);
  2127.         *sl = 0;
  2128.         if (words > 1) {
  2129.             output_possible=1;
  2130.             out_html("<HTML><HEAD><TITLE>Manpage of ");
  2131.             out_html(wordlist[0]);
  2132.             out_html("</TITLE>\n");
  2133.             out_html("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n");
  2134.             out_html("</HEAD><BODY>\n<H1>");
  2135.             out_html(wordlist[0]);
  2136.             out_html("</H1>\nSection: ");
  2137.             if (words>4)
  2138.             out_html(wordlist[4]);
  2139.             else
  2140.             out_html(section_name(wordlist[1]));
  2141.             out_html(" (");
  2142.             out_html(wordlist[1]);
  2143.             if (words>2) {
  2144.             out_html(")<BR>Updated: ");
  2145.             scan_troff(wordlist[2], 1, NULL);
  2146.             } else out_html(")");
  2147.             out_html("<BR><A HREF=\"#index\">Index</A>\n");
  2148.             man_page_html(0,0);    /* Return to Main Contents */
  2149.             *sl='\n';
  2150.             out_html("<HR>\n");
  2151.             if (mandoc_command) out_html("<BR>BSD mandoc<BR>");
  2152.         }
  2153.         c = sl+1;
  2154.         } else
  2155.         c = skip_till_newline(c);
  2156.         curpos=0;
  2157.         break;
  2158.     case V('T','X'):
  2159.         sl=fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
  2160.         *sl=0;
  2161.         out_html(change_to_font('I'));
  2162.         if (words>1) wordlist[1][-1]=0;
  2163.         c=lookup_abbrev(wordlist[0]);
  2164.         curpos+=strlen(c);
  2165.         out_html(c);
  2166.         out_html(change_to_font('R'));
  2167.         if (words>1)
  2168.         out_html(wordlist[1]);
  2169.         *sl='\n';
  2170.         c=sl+1;
  2171.         break;
  2172.     case V('r','m'):
  2173.             /* .rm xx : Remove request, macro or string */
  2174.     case V('r','n'):
  2175.             /* .rn xx yy : Rename request, macro or string xx to yy */
  2176.         {
  2177.         STRDEF *de;
  2178.         c=c+j;
  2179.         i=V(c[0],c[1]);
  2180.         c=c+2;
  2181.         while (isspace(*c) && *c!='\n') c++;
  2182.         j=V(c[0],c[1]);
  2183.         while (*c && *c!='\n') c++;
  2184.         c++;
  2185.         de=strdef;
  2186.         while (de && de->nr!=j) de=de->next;
  2187.         if (de) {
  2188.             if (de->st) free(de->st);
  2189.             de->nr=0;
  2190.         }
  2191.         de=strdef;
  2192.         while (de && de->nr!=i) de=de->next;
  2193.         if (de) de->nr=j;
  2194.         break;
  2195.         }
  2196.     case V('n','x'):
  2197.             /* .nx filename : next file. */
  2198.     case V('i','n'):
  2199.             /* .in +-N : Indent */
  2200.         c=skip_till_newline(c);
  2201.         break;
  2202.     case V('n','r'):
  2203.             /* .nr R +-N M: define and set number register R by +-N;
  2204.         **  auto-increment by M
  2205.         */
  2206.         {
  2207.         INTDEF *intd;
  2208.         c=c+j;
  2209.         i=V(c[0],c[1]);
  2210.         c=c+2;
  2211.         intd=intdef;
  2212.         while (intd && intd->nr!=i) intd=intd->next;
  2213.         if (!intd) {
  2214.             intd = (INTDEF*) xmalloc(sizeof(INTDEF));
  2215.             intd->nr=i;
  2216.             intd->val=0;
  2217.             intd->incr=0;
  2218.             intd->next=intdef;
  2219.             intdef=intd;
  2220.         }
  2221.         while (*c == ' ' || *c == '\t') c++;
  2222.         c=scan_expression(c,&intd->val);
  2223.         if (*c!='\n') {
  2224.             while (*c == ' ' || *c == '\t') c++;
  2225.             c=scan_expression(c,&intd->incr);
  2226.         }
  2227.         c=skip_till_newline(c);
  2228.         break;
  2229.         }
  2230.     case V('a','m'):
  2231.             /* .am xx yy : append to a macro. */
  2232.             /* define or handle as .ig yy */
  2233.         mode=1;
  2234.     case V('d','e'):
  2235.             /* .de xx yy : define or redefine macro xx; end at .yy (..) */
  2236.             /* define or handle as .ig yy */
  2237.         {
  2238.         STRDEF *de;
  2239.         int olen=0;
  2240.         c=c+j;
  2241.         sl=fill_words(c, wordlist, SIZE(wordlist), &words, '\n');
  2242.         i=V(c[0],c[1]);j=2;
  2243.         if (words == 1) wordlist[1]=".."; else {
  2244.             wordlist[1]--;
  2245.             wordlist[1][0]='.';
  2246.             j=3;
  2247.         }
  2248.         c=sl+1;
  2249.         sl=c;
  2250.         while (*c && strncmp(c,wordlist[1],j)) c=skip_till_newline(c);
  2251.         de=defdef;
  2252.         while (de && de->nr!= i) de=de->next;
  2253.         if (mode && de) olen=strlen(de->st);
  2254.         j=olen+c-sl;
  2255.         h= (char*) xmalloc((j*2+4)*sizeof(char));
  2256.         if (h) {
  2257.             for (j=0; j<olen; j++)
  2258.             h[j]=de->st[j];
  2259.             if (!j || h[j-1]!='\n')
  2260.             h[j++]='\n';
  2261.             while (sl!=c) {
  2262.             if (sl[0] == '\\' && sl[1] == '\\') {
  2263.                 h[j++]='\\'; sl++;
  2264.             } else
  2265.                 h[j++]=*sl;
  2266.             sl++;
  2267.             }
  2268.             h[j]=0;
  2269.             if (de) {
  2270.             if (de->st) free(de->st);
  2271.             de->st=h;
  2272.             } else {
  2273.             de = (STRDEF*) xmalloc(sizeof(STRDEF));
  2274.             de->nr=i;
  2275.             de->next=defdef;
  2276.             de->st=h;
  2277.             defdef=de;
  2278.             }
  2279.         }
  2280.         }
  2281.         c=skip_till_newline(c);
  2282.         break;
  2283.  
  2284.     /* ----- BSD mandoc stuff below ----- */
  2285.     case V('U','x'):    /* BSD mandoc */
  2286.         c=c+j;
  2287.         out_html("UNIX");
  2288.         c=skip_till_newline(c);
  2289.         break;
  2290.     case V('A','t'):    /* BSD mandoc - called with arg V */
  2291.         c=c+j;
  2292.         out_html("AT&amp;T System");
  2293.         break;
  2294.     case V('B','l'):    /* BSD mandoc */
  2295.     {
  2296.         char *nl, t=0 /* just for gcc */;
  2297.         c=c+j;
  2298.         nl = strchr(c,'\n');
  2299.         if (nl) {
  2300.          t = *nl;
  2301.          *nl = 0;
  2302.         }
  2303.         if (strstr(c, "-bullet")) /* HTML Unnumbered List */
  2304.          dl_newlevel_type(UL);
  2305.         else if (strstr(c, "-enum")) /* HTML Ordered List */
  2306.          dl_newlevel_type(OL);
  2307.         else             /* HTML Descriptive List */
  2308.          dl_newlevel_type(DL);
  2309.         if (nl)
  2310.          *nl = t;
  2311.         if (fillout) out_html("<P>\n"); else {
  2312.          out_html(NEWLINE);
  2313.          NEWLINE[0]='\n';
  2314.         }
  2315.         curpos=0;
  2316.         c=skip_till_newline(c);
  2317.         break;
  2318.     }
  2319.     case V('E','l'):    /* BSD mandoc */
  2320.          c=c+j;
  2321.          dl_endlevel_type();
  2322.          if (fillout) out_html("<P>\n"); else {
  2323.           out_html(NEWLINE);
  2324.           NEWLINE[0]='\n';
  2325.          }
  2326.          curpos=0;
  2327.          c=skip_till_newline(c);
  2328.          break;
  2329.     case V('I','t'):    /* BSD mandoc */
  2330.          c=c+j;
  2331.          if (dl_type(DL)) {
  2332.           out_html("<DT>");
  2333.           out_html(change_to_font('B'));
  2334.           if (*c == '\n') {
  2335.                /* Don't allow embedded comms after a newline */
  2336.                c++;
  2337.                c=scan_troff(c,1,NULL);
  2338.           } else {
  2339.                /* Do allow embedded comms on the same line. */
  2340.                c=scan_troff_mandoc(c,1,NULL);
  2341.           }
  2342.           out_html(change_to_font('R'));
  2343.           out_html(NEWLINE);
  2344.           if (inXo)
  2345.                still_dd = 1;
  2346.           else
  2347.                out_html("<DD>");
  2348.          } else if (dl_type(UL) || dl_type(OL)) {
  2349.           out_html("<LI>");
  2350.           c=scan_troff_mandoc(c,1,NULL);
  2351.           out_html(NEWLINE);
  2352.          }
  2353.          if (fillout) curpos++; else curpos=0;
  2354.          break;
  2355.     case V('X','o'):    /* BSD mandoc */
  2356.          c=c+j;
  2357.          inXo = 1;
  2358.          break;
  2359.     case V('X','c'):    /* BSD mandoc - Xc closes an Xo */
  2360.          c=c+j;
  2361.          if (inXo) {
  2362.           if (still_dd)
  2363.                out_html("<DD>");
  2364.           inXo = 0;
  2365.          }
  2366.          break;
  2367.     case V('S','m'):    /* BSD mandoc - called with arg on/off */
  2368.          c=skip_till_newline(c);
  2369.          break;
  2370.     case V('B','k'):    /* BSD mandoc */
  2371.     case V('E','k'):    /* BSD mandoc */
  2372.     case V('D','d'):    /* BSD mandoc */
  2373.     case V('O','s'):    /* BSD mandoc */
  2374.          trans_char(c,'"','\a');
  2375.          c=c+j;
  2376.          if (*c == '\n') c++;
  2377.          c=scan_troff_mandoc(c, 1, NULL);
  2378.          out_html(NEWLINE);
  2379.          if (fillout) curpos++; else curpos=0;
  2380.          break;
  2381.     case V('B','t'):    /* BSD mandoc */
  2382.          trans_char(c,'"','\a');
  2383.          c=c+j;
  2384.          out_html(" is currently in beta test.");
  2385.          if (fillout) curpos++; else curpos=0;
  2386.          break;
  2387.     case V('B','x'):    /* BSD mandoc */
  2388.          trans_char(c,'"','\a');
  2389.          c=c+j;
  2390.          if (*c == '\n') c++;
  2391.          out_html("BSD ");
  2392.          c=scan_troff_mandoc(c, 1, NULL);
  2393.          if (fillout) curpos++; else curpos=0;
  2394.          break;
  2395.     case V('D','l'):    /* BSD mandoc */
  2396.          c=c+j;
  2397.          out_html(NEWLINE);
  2398.          out_html("<BLOCKQUOTE>");
  2399.          out_html(change_to_font('L'));
  2400.          if (*c == '\n') c++;
  2401.          c=scan_troff_mandoc(c, 1, NULL);
  2402.          out_html(change_to_font('R'));
  2403.          out_html("</BLOCKQUOTE>");
  2404.          if (fillout) curpos++; else curpos=0;
  2405.          break;
  2406.     case V('B','d'):    /* BSD mandoc */
  2407.     {            /* Seems like a kind of example/literal mode */
  2408.          char *nl, t=0 /* just for gcc */;
  2409.          c=c+j;
  2410.          nl = strchr(c,'\n');
  2411.          if (nl) {
  2412.           t = *nl;
  2413.           *nl = 0;
  2414.          }
  2415.          out_html(NEWLINE);
  2416.          mandoc_bd_options = 0; /* Remember options for terminating Bl */
  2417.          if (strstr(c, "-offset indent")) {
  2418.           mandoc_bd_options |= BD_INDENT;
  2419.           out_html("<BLOCKQUOTE>\n");
  2420.          }
  2421.          if (strstr(c, "-literal") || strstr(c, "-unfilled")) {
  2422.           if (fillout) {
  2423.                mandoc_bd_options |= BD_LITERAL;
  2424.                out_html(change_to_font(0));
  2425.                out_html(change_to_size('0'));
  2426.                out_html("<PRE>\n");
  2427.           }
  2428.           curpos=0;
  2429.           fillout=0;
  2430.          }
  2431.          if (nl)
  2432.           *nl = t;
  2433.          c=skip_till_newline(c);
  2434.          break;
  2435.     }
  2436.     case V('E','d'):    /* BSD mandoc */
  2437.          if (mandoc_bd_options & BD_LITERAL) {
  2438.           if (!fillout) {
  2439.                out_html(change_to_font(0));
  2440.                out_html(change_to_size('0'));
  2441.                out_html("</PRE>\n");
  2442.           }
  2443.          }
  2444.          if (mandoc_bd_options & BD_INDENT)
  2445.           out_html("</BLOCKQUOTE>\n");
  2446.          curpos=0;
  2447.          fillout=1;
  2448.          c=skip_till_newline(c);
  2449.          break;
  2450.     case V('B','e'):    /* BSD mandoc */
  2451.          c=c+j;
  2452.          if (fillout) out_html("<P>"); else {
  2453.           out_html(NEWLINE);
  2454.           NEWLINE[0]='\n';
  2455.          }
  2456.          curpos=0;
  2457.          c=skip_till_newline(c);
  2458.          break;
  2459.     case V('X','r'):    /* BSD mandoc */
  2460.     {
  2461.          /* Translate xyz 1 to xyz(1)
  2462.           * Allow for multiple spaces.  Allow the section to be missing.
  2463.           */
  2464.          char buff[100];
  2465.          char *bufptr;
  2466.          trans_char(c,'"','\a');
  2467.          bufptr = buff;
  2468.          c = c+j;
  2469.          if (*c == '\n') c++; /* Skip spaces */
  2470.          while (isspace(*c) && *c != '\n') c++;
  2471.          while (isalnum(*c) && bufptr < buff + SIZE(buff)-4) {
  2472.           /* Copy the xyz part */
  2473.           *bufptr++ = *c++;
  2474.          }
  2475.          while (isspace(*c) && *c != '\n') c++;    /* Skip spaces */
  2476.          if (isdigit(*c)) { /* Convert the number if there is one */
  2477.           *bufptr++ = '(';
  2478.           while (isalnum(*c) && bufptr < buff + SIZE(buff)-3) {
  2479.                *bufptr++ = *c++;
  2480.           }
  2481.           *bufptr++ = ')';
  2482.          }
  2483.          while (*c != '\n' && bufptr < buff + SIZE(buff)-2) {
  2484.           /* Copy the remainder */
  2485.           if (!isspace(*c)) {
  2486.                *bufptr++ = *c;
  2487.           }
  2488.           c++;
  2489.          }
  2490.          *bufptr++ = '\n';
  2491.          *bufptr = 0;
  2492.          scan_troff_mandoc(buff, 1, NULL);
  2493.          out_html(NEWLINE);
  2494.          if (fillout) curpos++; else curpos=0;
  2495.     }
  2496.     break;
  2497.     case V('F','l'):    /* BSD mandoc */
  2498.          trans_char(c,'"','\a');
  2499.          c=c+j;
  2500.          out_html("-");
  2501.          if (*c!='\n') {
  2502.           out_html(change_to_font('B'));
  2503.           c=scan_troff_mandoc(c, 1, NULL);
  2504.           out_html(change_to_font('R'));
  2505.          }
  2506.          out_html(NEWLINE);
  2507.          if (fillout) curpos++; else curpos=0;
  2508.          break;
  2509.     case V('P','a'):    /* BSD mandoc */
  2510.     case V('P','f'):    /* BSD mandoc */
  2511.          trans_char(c,'"','\a');
  2512.          c=c+j;
  2513.          if (*c == '\n') c++;
  2514.          c=scan_troff_mandoc(c, 1, NULL);
  2515.          out_html(NEWLINE);
  2516.          if (fillout) curpos++; else curpos=0;
  2517.          break;
  2518.     case V('P','p'):    /* BSD mandoc */
  2519.          if (fillout) out_html("<P>\n"); else {
  2520.           out_html(NEWLINE);
  2521.           NEWLINE[0]='\n';
  2522.          }
  2523.          curpos=0;
  2524.          c=skip_till_newline(c);
  2525.          break;
  2526.     case V('D','q'):    /* BSD mandoc */
  2527.          trans_char(c,'"','\a');
  2528.          c=c+j;
  2529.          if (*c == '\n') c++;
  2530.          out_html("``");
  2531.          c=scan_troff_mandoc(c, 1, NULL);
  2532.          out_html("''");
  2533.          out_html(NEWLINE);
  2534.          if (fillout) curpos++; else curpos=0;
  2535.          break;
  2536.     case V('O','p'):    /* BSD mandoc */
  2537.          trans_char(c,'"','\a');
  2538.          c=c+j;
  2539.          if (*c == '\n') c++;
  2540.          out_html(change_to_font('R'));
  2541.          out_html("[");
  2542.          c=scan_troff_mandoc(c, 1, NULL);
  2543.          out_html(change_to_font('R'));
  2544.          out_html("]");
  2545.          out_html(NEWLINE);
  2546.          if (fillout) curpos++; else curpos=0;
  2547.          break;
  2548.     case V('O','o'):    /* BSD mandoc */
  2549.          trans_char(c,'"','\a');
  2550.          c=c+j;
  2551.          if (*c == '\n') c++;
  2552.          out_html(change_to_font('R'));
  2553.          out_html("[");
  2554.          c=scan_troff_mandoc(c, 1, NULL);
  2555.          if (fillout) curpos++; else curpos=0;
  2556.          break;
  2557.     case V('O','c'):    /* BSD mandoc */
  2558.          trans_char(c,'"','\a');
  2559.          c=c+j;
  2560.          c=scan_troff_mandoc(c, 1, NULL);
  2561.          out_html(change_to_font('R'));
  2562.          out_html("]");
  2563.          if (fillout) curpos++; else curpos=0;
  2564.          break;
  2565.     case V('P','q'):    /* BSD mandoc */
  2566.          trans_char(c,'"','\a');
  2567.          c=c+j;
  2568.          if (*c == '\n') c++;
  2569.          out_html("(");
  2570.          c=scan_troff_mandoc(c, 1, NULL);
  2571.          out_html(")");
  2572.          out_html(NEWLINE);
  2573.          if (fillout) curpos++; else curpos=0;
  2574.          break;
  2575.     case V('Q','l'):    /* BSD mandoc */
  2576.     {            /* Single quote first word in the line */
  2577.          char *sp;
  2578.          trans_char(c,'"','\a');
  2579.          c=c+j;
  2580.          if (*c == '\n') c++;
  2581.          sp = c;
  2582.          do {        /* Find first whitespace after the
  2583.                  * first word that isn't a mandoc macro
  2584.                  */
  2585.           while (*sp && isspace(*sp)) sp++;
  2586.           while (*sp && !isspace(*sp)) sp++;
  2587.          } while (*sp && isupper(*(sp-2)) && islower(*(sp-1)));
  2588.  
  2589.             /* Use a newline to mark the end of text to
  2590.              * be quoted
  2591.              */
  2592.          if (*sp) *sp = '\n';
  2593.          out_html("`");    /* Quote the text */
  2594.          c=scan_troff_mandoc(c, 1, NULL);
  2595.          out_html("'");
  2596.          out_html(NEWLINE);
  2597.          if (fillout) curpos++; else curpos=0;
  2598.          break;
  2599.     }
  2600.     case V('S','q'):    /* BSD mandoc */
  2601.          trans_char(c,'"','\a');
  2602.          c=c+j;
  2603.          if (*c == '\n') c++;
  2604.          out_html("`");
  2605.          c=scan_troff_mandoc(c, 1, NULL);
  2606.          out_html("'");
  2607.          out_html(NEWLINE);
  2608.          if (fillout) curpos++; else curpos=0;
  2609.          break;
  2610.     case V('A','r'):    /* BSD mandoc */
  2611.          /* parse one line in italics */
  2612.          out_html(change_to_font('I'));
  2613.          trans_char(c,'"','\a');
  2614.          c=c+j;
  2615.          if (*c == '\n') {    /* An empty Ar means "file ..." */
  2616.           out_html("file ...");
  2617.          } else {
  2618.           c=scan_troff_mandoc(c, 1, NULL);
  2619.          }
  2620.          out_html(change_to_font('R'));
  2621.          out_html(NEWLINE);
  2622.          if (fillout) curpos++; else curpos=0;
  2623.          break;
  2624.     case V('A','d'):    /* BSD mandoc */
  2625.     case V('E','m'):    /* BSD mandoc */
  2626.     case V('V','a'):    /* BSD mandoc */
  2627.          /* parse one line in italics */
  2628.          out_html(change_to_font('I'));
  2629.          trans_char(c,'"','\a');
  2630.          c=c+j;
  2631.          if (*c == '\n') c++;
  2632.          c=scan_troff_mandoc(c, 1, NULL);
  2633.          out_html(change_to_font('R'));
  2634.          out_html(NEWLINE);
  2635.          if (fillout) curpos++; else curpos=0;
  2636.          break;
  2637.     case V('N','d'):    /* BSD mandoc */
  2638.          trans_char(c,'"','\a');
  2639.          c=c+j;
  2640.          if (*c == '\n') c++;
  2641.          out_html(" - ");
  2642.          c=scan_troff_mandoc(c, 1, NULL);
  2643.          out_html(NEWLINE);
  2644.          if (fillout) curpos++; else curpos=0;
  2645.          break;
  2646.     case V('N','m'):    /* BSD mandoc */
  2647.     {
  2648.          static char *mandoc_name = 0;
  2649.          trans_char(c,'"','\a');
  2650.          c=c+j;
  2651.          if (mandoc_synopsis) {
  2652.           /*
  2653.            * Break lines only in the Synopsis.
  2654.            * The Synopsis section seems to be treated
  2655.            * as a special case - Bummer!
  2656.            */
  2657.           static int count = 0; /* Don't break on the first Nm */
  2658.           if (count) {
  2659.                out_html("<BR>");
  2660.           } else {
  2661.                char *end, t=0 /* just for gcc */;
  2662.                end = strchr(c, '\n');
  2663.                if (end) {
  2664.                 t = *end;
  2665.                 *end = 0;
  2666.                }
  2667.                if (mandoc_name)
  2668.                 free(mandoc_name);
  2669.                mandoc_name = xstrdup(c);
  2670.                if (end)
  2671.                 *end = t;
  2672.           }
  2673.           count++;
  2674.          }
  2675.          out_html(change_to_font('B'));
  2676.          while (*c == ' ' || *c == '\t') c++;
  2677.          if (*c == '\n') {
  2678.           /*
  2679.            * If Nm has no argument, use one from an earlier
  2680.            * Nm command that did have one.  Hope there aren't
  2681.            * too many commands that do this.
  2682.            */
  2683.           if (mandoc_name)
  2684.                out_html(mandoc_name);
  2685.          } else {
  2686.           c=scan_troff_mandoc(c, 1, NULL);
  2687.          }
  2688.          out_html(change_to_font('R'));
  2689.          out_html(NEWLINE);
  2690.          if (fillout) curpos++; else curpos=0;
  2691.          break;
  2692.     }
  2693.     case V('C','d'):    /* BSD mandoc */
  2694.     case V('C','m'):    /* BSD mandoc */
  2695.     case V('I','c'):    /* BSD mandoc */
  2696.     case V('M','s'):    /* BSD mandoc */
  2697.     case V('O','r'):    /* BSD mandoc */
  2698.     case V('S','y'):    /* BSD mandoc */
  2699.          /* parse one line in bold */
  2700.          out_html(change_to_font('B'));
  2701.          trans_char(c,'"','\a');
  2702.          c=c+j;
  2703.          if (*c == '\n') c++;
  2704.          c=scan_troff_mandoc(c, 1, NULL);
  2705.          out_html(change_to_font('R'));
  2706.          out_html(NEWLINE);
  2707.          if (fillout) curpos++; else curpos=0;
  2708.          break;
  2709.     case V('D','v'):    /* BSD mandoc */
  2710.     case V('E','v'):    /* BSD mandoc */
  2711.     case V('F','r'):    /* BSD mandoc */
  2712.     case V('L','i'):    /* BSD mandoc */
  2713.     case V('N','o'):    /* BSD mandoc */
  2714.     case V('N','s'):    /* BSD mandoc */
  2715.     case V('T','n'):    /* BSD mandoc */
  2716.     case V('n','N'):    /* BSD mandoc */
  2717.          trans_char(c,'"','\a');
  2718.          c=c+j;
  2719.          if (*c == '\n') c++;
  2720.          out_html(change_to_font('B'));
  2721.          c=scan_troff_mandoc(c, 1, NULL);
  2722.          out_html(change_to_font('R'));
  2723.          out_html(NEWLINE);
  2724.          if (fillout) curpos++; else curpos=0;
  2725.          break;
  2726.     case V('%','A'):    /* BSD mandoc biblio stuff */
  2727.     case V('%','D'):
  2728.     case V('%','N'):
  2729.     case V('%','O'):
  2730.     case V('%','P'):
  2731.     case V('%','Q'):
  2732.     case V('%','V'):
  2733.          c=c+j;
  2734.          if (*c == '\n') c++;
  2735.          c=scan_troff(c, 1, NULL); /* Don't allow embedded mandoc coms */
  2736.          if (fillout) curpos++; else curpos=0;
  2737.          break;
  2738.     case V('%','B'):
  2739.     case V('%','J'):
  2740.     case V('%','R'):
  2741.     case V('%','T'):
  2742.          c=c+j;
  2743.          out_html(change_to_font('I'));
  2744.          if (*c == '\n') c++;
  2745.          c=scan_troff(c, 1, NULL); /* Don't allow embedded mandoc coms */
  2746.          out_html(change_to_font('R'));
  2747.          if (fillout) curpos++; else curpos=0;
  2748.          break;
  2749.         /* ----- end of BSD mandoc stuff ----- */
  2750.  
  2751.      default:
  2752.              /* search macro database of self-defined macros */
  2753.          owndef = defdef;
  2754.         while (owndef && owndef->nr!=i) owndef=owndef->next;
  2755.         if (owndef) {
  2756.         char **oldargument;
  2757.         int deflen;
  2758.         int onff;
  2759.         sl=fill_words(c+j, wordlist, SIZE(wordlist), &words, '\n');
  2760.         c=sl+1;
  2761.         *sl=0;
  2762.         for (i=1; i<words; i++)
  2763.             wordlist[i][-1]=0;
  2764.         for (i=0; i<words; i++) {
  2765.             char *h=NULL;
  2766.             if (mandoc_command)
  2767.              scan_troff_mandoc(wordlist[i],1,&h);
  2768.             else
  2769.              scan_troff(wordlist[i],1,&h);
  2770.             wordlist[i]=h;
  2771.         }
  2772.         for (i=words; i<SIZE(wordlist); i++)
  2773.             wordlist[i]=NULL;
  2774.         deflen = strlen(owndef->st);
  2775.         owndef->st[deflen+1]='a';
  2776.         for (i=0; (owndef->st[deflen+2+i] = owndef->st[i]); i++);
  2777.         oldargument=argument;
  2778.         argument=wordlist;
  2779.         onff=newline_for_fun;
  2780.         if (mandoc_command)
  2781.              scan_troff_mandoc(owndef->st+deflen+2, 0, NULL);
  2782.         else
  2783.              scan_troff(owndef->st+deflen+2, 0, NULL);
  2784.         newline_for_fun=onff;
  2785.         argument=oldargument;
  2786.         for (i=0; i<words; i++) if (wordlist[i]) free(wordlist[i]);
  2787.         *sl='\n';
  2788.         } else if (mandoc_command &&
  2789.                ((isupper(*c) && islower(c[1]))
  2790.             || (islower(*c) && isupper(c[1])))) {
  2791.          /*
  2792.           * Let through any BSD mandoc commands that haven't
  2793.           * been dealt with.
  2794.           * I don't want to miss anything out of the text.
  2795.           */
  2796.                char buf[4];
  2797.                strncpy(buf,c,2);
  2798.                buf[2] = ' ';
  2799.                buf[3] = 0;
  2800.                out_html(buf);  /* Print the command (it might just be text). */
  2801.                c=c+j;
  2802.                trans_char(c,'"','\a');
  2803.                if (*c == '\n') c++;     /* really? */
  2804.                out_html(change_to_font('R'));
  2805.                c=scan_troff(c, 1, NULL);
  2806.                out_html(NEWLINE);
  2807.                if (fillout) curpos++; else curpos=0;
  2808.         } else
  2809.         c=skip_till_newline(c);
  2810.         break;
  2811.     }
  2812.     }
  2813.     if (fillout) { out_html(NEWLINE); curpos++; }
  2814.     NEWLINE[0]='\n';
  2815.     return c;
  2816. }
  2817.  
  2818. static int contained_tab=0;
  2819. static int mandoc_line=0;/* Signals whether to look for embedded mandoc cmds */
  2820.  
  2821. static char *
  2822. scan_troff(char *c, int san, char **result) {   /* san : stop at newline */
  2823.     char *h;
  2824.     char intbuff[500];
  2825.     int ibp=0;
  2826. #define FLUSHIBP  if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
  2827.     char *exbuffer;
  2828.     int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun;
  2829.     int usenbsp = 0;
  2830.  
  2831.     exbuffer = buffer;
  2832.     exbuffpos = buffpos;
  2833.     exbuffmax = buffmax;
  2834.     exnewline_for_fun = newline_for_fun;
  2835.     exscaninbuff = scaninbuff;
  2836.     newline_for_fun = 0;
  2837.     if (result) {
  2838.     if (*result) {
  2839.         buffer = *result;
  2840.         buffpos = strlen(buffer);
  2841.         buffmax = buffpos;
  2842.     } else {
  2843.         buffer = (char *) xmalloc(1000*sizeof(char));
  2844.         buffpos = 0;
  2845.         buffmax = 1000;
  2846.     }
  2847.     scaninbuff = 1;
  2848.     }
  2849.     h = c;
  2850.     /* start scanning */
  2851.     while (*h && (!san || newline_for_fun || *h != '\n')) {
  2852.     if (*h == escapesym) {
  2853.         h++;
  2854.         FLUSHIBP;
  2855.         h = scan_escape(h);
  2856.     } else if (*h == controlsym && h[-1] == '\n') {
  2857.         h++;
  2858.         FLUSHIBP;
  2859.         h = scan_request(h);
  2860.         if (san && h[-1] == '\n') h--;
  2861.     } else if (mandoc_line
  2862.            && *(h) && isupper(*(h))
  2863.            && *(h+1) && islower(*(h+1))
  2864.            && *(h+2) && isspace(*(h+2))) {
  2865.          /* BSD imbedded command eg ".It Fl Ar arg1 Fl Ar arg2" */
  2866.          FLUSHIBP;
  2867.          h = scan_request(h);
  2868.          if (san && h[-1] == '\n') h--;
  2869.     } else if (*h == nobreaksym && h[-1] == '\n') {
  2870.         h++;
  2871.         FLUSHIBP;
  2872.         h = scan_request(h);
  2873.         if (san && h[-1] == '\n') h--;
  2874.     } else {
  2875.         if (h[-1] == '\n' && still_dd && isalnum(*h)) {
  2876.         /* sometimes a .HP request is not followed by a .br request */
  2877.         FLUSHIBP;
  2878.         out_html("<DD>");
  2879.         curpos=0;
  2880.         still_dd=0;
  2881.         }
  2882.         switch (*h) {
  2883.         case '&':
  2884.         intbuff[ibp++]='&';
  2885.         intbuff[ibp++]='a';
  2886.         intbuff[ibp++]='m';
  2887.         intbuff[ibp++]='p';
  2888.         intbuff[ibp++]=';';
  2889.         curpos++;
  2890.         break;
  2891.         case '<':
  2892.         intbuff[ibp++]='&';
  2893.         intbuff[ibp++]='l';
  2894.         intbuff[ibp++]='t';
  2895.         intbuff[ibp++]=';';
  2896.         curpos++;
  2897.         break;
  2898.         case '>':
  2899.         intbuff[ibp++]='&';
  2900.         intbuff[ibp++]='g';
  2901.         intbuff[ibp++]='t';
  2902.         intbuff[ibp++]=';';
  2903.         curpos++;
  2904.         break;
  2905.         case '"':
  2906.         intbuff[ibp++]='&';
  2907.         intbuff[ibp++]='q';
  2908.         intbuff[ibp++]='u';
  2909.         intbuff[ibp++]='o';
  2910.         intbuff[ibp++]='t';
  2911.         intbuff[ibp++]=';';
  2912.         curpos++;
  2913.         break;
  2914.         case '\n':
  2915.         if (h[-1] == '\n' && fillout) {
  2916.             intbuff[ibp++]='<';
  2917.             intbuff[ibp++]='P';
  2918.             intbuff[ibp++]='>';
  2919.         }
  2920.         if (contained_tab && fillout) {
  2921.             intbuff[ibp++]='<';
  2922.             intbuff[ibp++]='B';
  2923.             intbuff[ibp++]='R';
  2924.             intbuff[ibp++]='>';
  2925.         }
  2926.         contained_tab=0;
  2927.         curpos=0;
  2928.         usenbsp=0;
  2929.         intbuff[ibp++]='\n';
  2930.         break;
  2931.         case '\t':
  2932.         {
  2933.             int curtab=0;
  2934.             contained_tab=1;
  2935.             FLUSHIBP;
  2936.             /* like a typewriter, not like TeX */
  2937.             tabstops[SIZE(tabstops)-1] = curpos+1;
  2938.             while (curtab < maxtstop && tabstops[curtab] <= curpos)
  2939.             curtab++;
  2940.             if (curtab < maxtstop) {
  2941.             if (!fillout) {
  2942.                 while (curpos<tabstops[curtab]) {
  2943.                 intbuff[ibp++]=' ';
  2944.                 if (ibp>480) { FLUSHIBP; }
  2945.                 curpos++;
  2946.                 }
  2947.             } else {
  2948.                 out_html("<TT>");
  2949.                 while (curpos < tabstops[curtab]) {
  2950.                 out_html("&nbsp;");
  2951.                 curpos++;
  2952.                 }
  2953.                 out_html("</TT>");
  2954.             }
  2955.             }
  2956.         }
  2957.         break;
  2958.         default:
  2959.         if (*h == ' ' && (h[-1] == '\n' || usenbsp)) {
  2960.             FLUSHIBP;
  2961.             if (!usenbsp && fillout) {
  2962.             out_html("<BR>");
  2963.             curpos=0;
  2964.             }
  2965.             usenbsp=fillout;
  2966.             if (usenbsp) out_html("&nbsp;"); else intbuff[ibp++]=' ';
  2967.         } else if (*h > 31 && *h < 127) {
  2968.             intbuff[ibp++]=*h;
  2969.         } else if (((unsigned char)(*h)) > 127) {
  2970. #ifdef NO_8BIT
  2971.             intbuff[ibp++]='&';
  2972.             intbuff[ibp++]='#';
  2973.             intbuff[ibp++]='0'+((unsigned char)(*h))/100;
  2974.             intbuff[ibp++]='0'+(((unsigned char)(*h))%100)/10;
  2975.             intbuff[ibp++]='0'+((unsigned char)(*h))%10;
  2976.             intbuff[ibp++]=';';
  2977. #else
  2978.             intbuff[ibp++]=*h;
  2979. #endif
  2980.         }
  2981.         curpos++;
  2982.         break;
  2983.         }
  2984.         if (ibp>480) FLUSHIBP;
  2985.         h++;
  2986.     }
  2987.     }
  2988.     FLUSHIBP;
  2989.     if (buffer) buffer[buffpos]=0;
  2990.     if (san && *h) h++;
  2991.     newline_for_fun=exnewline_for_fun;
  2992.     if (result) {
  2993.     *result = buffer;
  2994.     buffer=exbuffer;
  2995.     buffpos=exbuffpos;
  2996.     buffmax=exbuffmax;
  2997.     scaninbuff=exscaninbuff;
  2998.     }
  2999.     return h;
  3000. }
  3001.  
  3002. static char *scan_troff_mandoc(char *c, int san, char **result) {
  3003.      char *ret, *end = c;
  3004.      int oldval = mandoc_line;
  3005.      mandoc_line = 1;
  3006.      while (*end && *end != '\n') {
  3007.       end++;
  3008.      }
  3009.  
  3010.      if (end > c + 2
  3011.      && ispunct(*(end - 1))
  3012.      && isspace(*(end - 2)) && *(end - 2) != '\n') {
  3013.       /*
  3014.        * Don't format lonely punctuation. E.g. in "xyz ," format
  3015.        * the xyz and then append the comma removing the space.
  3016.        */
  3017.       *(end - 2) = '\n';
  3018.       ret = scan_troff(c, san, result);
  3019.       *(end - 2) = *(end - 1);
  3020.       *(end - 1) = ' ';
  3021.      } else {
  3022.       ret = scan_troff(c, san, result);
  3023.      }
  3024.      mandoc_line = oldval;
  3025.      return ret;
  3026. }
  3027.  
  3028. STRDEF *foundpages=NULL;
  3029.  
  3030. #define BUFSMSG 1024
  3031. static void
  3032. error_page(char *s, char *t, ...) {
  3033.     va_list p;
  3034.     char buf[BUFSMSG];
  3035.     char notify_buf[BUFSMSG+5];
  3036.     va_start(p, t);
  3037.     vsnprintf(buf, BUFSMSG, t, p);
  3038.     va_end(p);
  3039. #ifdef _KOLIBRI
  3040.     snprintf(notify_buf, BUFSMSG+5, "'%s' -E", buf);
  3041.     _ksys_exec("/sys/@notify", buf);
  3042. #else
  3043.     printf("%s %s\n", s, buf);
  3044. #endif
  3045.     exit(0);
  3046. }
  3047.  
  3048. char *
  3049. xstrdup(const char *s) {
  3050.      char *p = strdup(s);
  3051.      if (p == NULL)
  3052.       error_page("Out of memory",
  3053.              "Sorry, out of memory, aborting...\n");
  3054.      return p;
  3055. }
  3056.  
  3057. void *
  3058. xmalloc(size_t size) {
  3059.      void *p = malloc(size);
  3060.      if (p == NULL)
  3061.       error_page("Out of memory",
  3062.              "Sorry, out of memory, aborting...\n");
  3063.      return p;
  3064. }
  3065.  
  3066. void *
  3067. xrealloc(void *ptr, size_t size) {
  3068.      void *p = realloc(ptr,size);
  3069.      if (p == NULL)
  3070.       error_page("Out of memory",
  3071.              "Sorry, out of memory, aborting...\n");
  3072.      return p;
  3073. }
  3074.  
  3075. static void
  3076. usage(void) {
  3077. #ifdef _KOLIBRI
  3078.      _ksys_exec("/sys/@notify", "'Usage: man2html in_file [out_file.html]' -I");
  3079. #else
  3080.      puts("Usage: man2html in_file [out_file.html]");
  3081. #endif
  3082.      exit(0);
  3083. }
  3084.  
  3085. #if 0
  3086. static void
  3087. goto_dir(char *path, char **dir, char **name) {
  3088.      char *s, *t, *u;
  3089.  
  3090.      s = xstrdup(path);
  3091.      t = strrchr(s, '/');
  3092.      if (t) {
  3093.       *t = 0;
  3094.       u = strrchr(s, '/');
  3095.       *t = '/';
  3096.       if (u) {
  3097.           *u = 0;
  3098. #ifdef _KOLIBRI
  3099.           setcwd(s);
  3100. #else
  3101.           chdir(s);
  3102. #endif
  3103.           if (dir)
  3104.               *dir = s;
  3105.           if (name)
  3106.                *name = u+1;
  3107. #if 0
  3108.            else  /* complain or not - this need not be fatal */
  3109.             error_page("Error", "man2html: could not chdir to %s", s);
  3110. #endif
  3111.       }
  3112.      }
  3113. }
  3114. #endif
  3115.  
  3116. char
  3117. *temp_file_name(char* in_path){
  3118.     char* in_name = basename(in_path);
  3119.     #define PST_SIZE 5
  3120.     const char* pst = ".html";
  3121. #ifdef _KOLIBRI
  3122.     #define TMP_PATH_SIZE 9
  3123.     const char* tmp_path = "/tmp0/1/";
  3124. #else
  3125.     #define TMP_PATH_SIZE 2
  3126.     const char* tmp_path = "./";
  3127. #endif
  3128.     char* full_name = xmalloc((TMP_PATH_SIZE+strlen(in_name)+PST_SIZE+1)*sizeof(char));
  3129.     strcpy(full_name, tmp_path);
  3130.     strcat(full_name, in_name);
  3131.     strcat(full_name, pst);
  3132.     return full_name;
  3133. }
  3134.  
  3135. int
  3136. main(int argc, char **argv) {
  3137.     FILE *f;
  3138.     int l, c;
  3139.     char *buf, *filename, *fnam = NULL;
  3140.     char *outfilename;
  3141.    
  3142.     if (argc < 2){
  3143.         usage();
  3144.     }
  3145.    
  3146.     /* Find filename */
  3147.     if (argc > 1) {
  3148.         fnam = argv[1];
  3149.         outfilename = temp_file_name(fnam);
  3150.     }
  3151.     if (argc > 2) {
  3152.         outfilename = argv[2];
  3153.     }
  3154.  
  3155.     if ((out = fopen(outfilename, "w")) == NULL) {
  3156.         error_page("Error!", "Cannot open file %s", outfilename);
  3157.         return 0;
  3158.     }
  3159.  
  3160.     filename = fnam;
  3161.     //directory = 0;
  3162.  
  3163.     /* Open input file */
  3164.      //goto_dir(fnam, &directory, &fnam);
  3165.  
  3166.      f = fopen(fnam, "r");
  3167.      if (f == NULL)
  3168.           error_page("File not found", "Could not open %s\n", filename);
  3169.      fname = fnam;
  3170.  
  3171.     /* Read entire file into buf[1..l] */
  3172. #define XTRA 5
  3173.     /* buf has 1 extra byte at the start, and XTRA extra bytes at the end */
  3174.     int ct;
  3175.  
  3176.     l = 0;
  3177.  
  3178. #ifdef _KOLIBRI
  3179.     ksys_bdfe_t bdfe;
  3180.     _ksys_file_get_info(filename, &bdfe);
  3181.     l = bdfe.size;
  3182. #else
  3183.     struct stat stbuf;
  3184.     if (stat(filename, &stbuf) != -1) l=stbuf.st_size;
  3185. #endif
  3186.  
  3187.     buf = (char *) xmalloc((l+1+XTRA)*sizeof(char));
  3188.     ct = fread(buf+1,1,l,f);
  3189.     if (ct < l)
  3190.         l = ct;
  3191.     fclose(f);
  3192.  
  3193.     buf[0] = '\n';
  3194.     buf[l+1] = '\n';
  3195.     buf[l+2] = buf[l+3] = 0;
  3196.  
  3197. #ifdef MAKEINDEX
  3198.     idxfile = fopen(INDEXFILE, "a");
  3199. #endif
  3200.     stdinit();
  3201.     scan_troff(buf+1,0,NULL);
  3202.     dl_down();
  3203.     out_html(change_to_font(0));
  3204.     out_html(change_to_size(0));
  3205.     if (!fillout) {
  3206.     fillout=1;
  3207.     out_html("</PRE>");
  3208.     }
  3209.     out_html(NEWLINE);
  3210.     if (output_possible) {
  3211.     /* &nbsp; for mosaic users */
  3212.     fprintf(out, "<HR>\n<A NAME=\"index\">&nbsp;</A><H2>Index</H2>\n<DL>\n");
  3213.     manidx[mip]=0;
  3214.     fprintf(out, "%s", manidx);
  3215.     if (subs) fprintf(out,"</DL>\n");
  3216.     fprintf(out, "</DL>\n");
  3217.     print_sig();
  3218.     fprintf(out, "</BODY>\n</HTML>\n");
  3219.     } else {
  3220.     if (!filename)
  3221.          filename = fname;
  3222.     if (*filename == '/')
  3223.          error_page("Invalid Manpage",
  3224.            "The requested file %s is not a valid (unformatted) "
  3225.            "man page.\nIf the file is a formatted manpage, "
  3226.            "you could try to load the\n"
  3227.            "<A HREF=\"file://localhost%s\">plain file</A>.\n",
  3228.            filename, filename);
  3229.     else
  3230.          error_page("Invalid Manpage",
  3231.            "The requested file %s is not a valid (unformatted) "
  3232.            "man page.", filename);
  3233.     }
  3234.     if (idxfile)
  3235.         fclose(idxfile);
  3236.     if (buf)
  3237.         free(buf);
  3238. #ifdef _KOLIBRI
  3239.     if(argc==2){
  3240.         _ksys_exec("/sys/network/webview", outfilename);
  3241.     }
  3242. #endif
  3243.     return 0;
  3244. }
  3245.