2 ** This program was written by Richard Verhoeven (NL:5482ZX35)
3 ** at the Eindhoven University of Technology. Email: rcb5@win.tue.nl
5 ** Permission is granted to distribute, modify and use this program as long
6 ** as this comment is not removed or changed.
9 ** If you want to use this program for your WWW server, adjust the line
10 ** which defines the CGIBASE or compile it with the -DCGIBASE='"..."' option.
12 ** You have to adjust the built-in manpath to your local system. Note that
13 ** every directory should start and end with the '/' and that the first
14 ** directory should be "/" to allow a full path as an argument.
16 ** The program first check if PATH_INFO contains some information.
17 ** If it does (t.i. man2html/some/thing is used), the program will look
18 ** for a manpage called PATH_INFO in the manpath.
20 ** Otherwise the manpath is searched for the specified command line argument,
21 ** where the following options can be used:
23 ** name name of manpage (csh, printf, xv, troff)
24 ** section the section (1 2 3 4 5 6 7 8 9 n l 1v ...)
25 ** -M path an extra directory to look for manpages (replaces "/")
27 ** If man2html finds multiple manpages that satisfy the options, an index
28 ** is displayed and the user can make a choice. If only one page is
29 ** found, that page will be displayed.
31 ** man2html will add links to the converted manpages. The function add_links
32 ** is used for that. At the moment it will add links as follows, where
33 ** indicates what should match to start with:
35 ** Recognition Item Link
36 ** ----------------------------------------------------------
37 ** name(*) Manpage ../man?/name.*
39 ** name@hostname Email address mailto:name@hostname
41 ** method://string URL method://string
43 ** www.host.name WWW server http://www.host.name
45 ** ftp.host.name FTP server ftp://ftp.host.name
47 ** <file.h> Include file file:/usr/include/file.h
50 ** Since man2html does not check if manpages, hosts or email addresses exist,
51 ** some links might not work. For manpages, some extra checks are performed
52 ** to make sure not every () pair creates a link. Also out of date pages
53 ** might point to incorrect places.
55 ** The program will not allow users to get system specific files, such as
56 ** /etc/passwd. It will check that "man" is part of the specified file and
57 ** that "/../" isn't. Even if someone manages to get such file, man2html will
58 ** handle it like a manpage and will usually not produce any output (or crash).
60 ** If you find any bugs when normal manpages are converted, please report
61 ** them to me (rcb5@win.tue.nl) after you have checked that man(1) can handle
62 ** the manpage correct.
64 ** Known bugs and missing features:
66 ** * Equations are not converted at all.
67 ** * Tables are converted but some features are not possible in html.
68 ** * The tabbing environment is converted by counting characters and adding
69 ** spaces. This might go wrong (outside <PRE>)
70 ** * Some pages look beter if man2html works in troff mode, especially pages
71 ** with tables. You can deside at compile time which made you want to use.
73 ** -DNROFF=0 troff mode
74 ** -DNROFF=1 nroff mode (default)
76 ** if you install both modes, you should compile with the correct CGIBASE.
77 ** * Some manpages rely on the fact that troff/nroff is used to convert
78 ** them and use features which are not descripted in the man manpages.
79 ** (definitions, calculations, conditionals, requests). I can't guarantee
80 ** that all these features work on all manpages. (I didn't have the
81 ** time to look through all the available manpages.)
92 #include <sys/types.h>
97 #define CGIBASE "http://wsinwp01.win.tue.nl:1234/cgi-bin/man2html"
104 char *signature
= "<HR>\n"
105 "This document was created by\n"
106 "<A HREF=\""CGIBASE
"\">man2html</A>,\n"
107 "using the manual pages.<BR>\n"
110 /* timeformat for signature */
111 #define TIMEFORMAT "%T GMT, %B %d, %Y"
113 char *manpath
[] = { "/",
127 "/usr/newsprint/man/",
130 char *sections
= "123456789nl";
134 printf("Content-type: text/html\n\n"
136 "<TITLE>Manual Pages</TITLE>\n"
138 "<H1>Manual Pages</H1>\n"
139 "This is a HyperText interface to the UNIX manpages.\n"
140 "You can enter a program name, the section, an extra\n"
141 "directory (using -M) or a full name. For example\n"
142 "<UL><LI><TT>elm</TT>\n"
143 "<LI><TT>elm 1</TT>\n"
144 "<LI><TT>-M /usr/local/man elm</TT>\n"
145 "<LI><TT>/local/gcc/man/man1/gperf.1</TT>\n"
149 "This man2html converter was written by \n"
150 "<A HREF=\"http://wsinwp01.win.tue.nl:1234/index.html\">"
151 "Richard Verhoeven</A>\n"
156 /* below this you should not change anything unless you know a lot
157 ** about this program or about troff.
161 typedef struct STRDEF STRDEF
;
168 typedef struct INTDEF INTDEF
;
176 static char NEWLINE
[2]="\n";
177 static char idxlabel
[6] = "ixAAA";
179 #define INDEXFILE "/tmp/manindex.list"
184 STRDEF
*chardef
, *strdef
, *defdef
;
187 #define V(A,B) ((A)*256+(B))
189 INTDEF standardint
[] = {
190 { V('n',' '), NROFF
,0, NULL
},
191 { V('t',' '), 1-NROFF
,0, NULL
},
192 { V('o',' '), 1,0, NULL
},
193 { V('e',' '), 0,0, NULL
},
194 { V('.','l'), 70,0,NULL
},
195 { V('.','$'), 0,0, NULL
},
196 { V('.','A'), NROFF
,0, NULL
},
197 { V('.','T'), 1-NROFF
,0, NULL
},
198 { V('.','V'), 1,0, NULL
}, /* the me package tests for this */
201 STRDEF standardstring
[] = {
202 { V('R',' '), 1, "®", NULL
},
203 { V('l','q'), 2, "``", NULL
},
204 { V('r','q'), 2, "''", NULL
},
209 STRDEF standardchar
[] = {
210 { V('*','*'), 1, "*", NULL
},
211 { V('*','A'), 1, "A", NULL
},
212 { V('*','B'), 1, "B", NULL
},
213 { V('*','C'), 2, "Xi", NULL
},
214 { V('*','D'), 5, "Delta", NULL
},
215 { V('*','E'), 1, "E", NULL
},
216 { V('*','F'), 3, "Phi", NULL
},
217 { V('*','G'), 5, "Gamma", NULL
},
218 { V('*','H'), 5, "Theta", NULL
},
219 { V('*','I'), 1, "I", NULL
},
220 { V('*','K'), 1, "K", NULL
},
221 { V('*','L'), 6, "Lambda", NULL
},
222 { V('*','M'), 1, "M", NULL
},
223 { V('*','N'), 1, "N", NULL
},
224 { V('*','O'), 1, "O", NULL
},
225 { V('*','P'), 2, "Pi", NULL
},
226 { V('*','Q'), 3, "Psi", NULL
},
227 { V('*','R'), 1, "P", NULL
},
228 { V('*','S'), 5, "Sigma", NULL
},
229 { V('*','T'), 1, "T", NULL
},
230 { V('*','U'), 1, "Y", NULL
},
231 { V('*','W'), 5, "Omega", NULL
},
232 { V('*','X'), 1, "X", NULL
},
233 { V('*','Y'), 1, "H", NULL
},
234 { V('*','Z'), 1, "Z", NULL
},
235 { V('*','a'), 5, "alpha", NULL
},
236 { V('*','b'), 4, "beta", NULL
},
237 { V('*','c'), 2, "xi", NULL
},
238 { V('*','d'), 5, "delta", NULL
},
239 { V('*','e'), 7, "epsilon", NULL
},
240 { V('*','f'), 3, "phi", NULL
},
241 { V('*','g'), 5, "gamma", NULL
},
242 { V('*','h'), 5, "theta", NULL
},
243 { V('*','i'), 4, "iota", NULL
},
244 { V('*','k'), 5, "kappa", NULL
},
245 { V('*','l'), 6, "lambda", NULL
},
246 { V('*','m'), 1, "µ", NULL
},
247 { V('*','n'), 2, "nu", NULL
},
248 { V('*','o'), 1, "o", NULL
},
249 { V('*','p'), 2, "pi", NULL
},
250 { V('*','q'), 3, "psi", NULL
},
251 { V('*','r'), 3, "rho", NULL
},
252 { V('*','s'), 5, "sigma", NULL
},
253 { V('*','t'), 3, "tau", NULL
},
254 { V('*','u'), 7, "upsilon", NULL
},
255 { V('*','w'), 5, "omega", NULL
},
256 { V('*','x'), 3, "chi", NULL
},
257 { V('*','y'), 3, "eta", NULL
},
258 { V('*','z'), 4, "zeta", NULL
},
259 { V('t','s'), 5, "sigma", NULL
},
260 { V('+','-'), 1, "±", NULL
},
261 { V('1','2'), 1, "½", NULL
},
262 { V('1','4'), 1, "¼", NULL
},
263 { V('3','4'), 1, "¾", NULL
},
264 { V('F','i'), 3, "ffi", NULL
},
265 { V('F','l'), 3, "ffl", NULL
},
266 { V('a','a'), 1, "´", NULL
},
267 { V('a','p'), 1, "~", NULL
},
268 { V('b','r'), 1, "|", NULL
},
269 { V('b','u'), 1, "*", NULL
},
270 { V('b','v'), 1, "|", NULL
},
271 { V('c','i'), 1, "o", NULL
},
272 { V('c','o'), 1, "©", NULL
},
273 { V('c','t'), 1, "¢", NULL
},
274 { V('d','e'), 1, "°", NULL
},
275 { V('d','g'), 1, "+", NULL
},
276 { V('d','i'), 1, "÷", NULL
},
277 { V('e','m'), 1, "-", NULL
},
278 { V('e','m'), 3, "---", NULL
},
279 { V('e','q'), 1, "=", NULL
},
280 { V('e','s'), 1, "Ø", NULL
},
281 { V('f','f'), 2, "ff", NULL
},
282 { V('f','i'), 2, "fi", NULL
},
283 { V('f','l'), 2, "fl", NULL
},
284 { V('f','m'), 1, "´", NULL
},
285 { V('g','a'), 1, "`", NULL
},
286 { V('h','y'), 1, "-", NULL
},
287 { V('l','c'), 2, "|¯", NULL
},
288 { V('l','f'), 2, "|_", NULL
},
289 { V('l','k'), 1, "<FONT SIZE=+2>{</FONT>", NULL
},
290 { V('m','i'), 1, "-", NULL
},
291 { V('m','u'), 1, "×", NULL
},
292 { V('n','o'), 1, "¬", NULL
},
293 { V('o','r'), 1, "|", NULL
},
294 { V('p','l'), 1, "+", NULL
},
295 { V('r','c'), 2, "¯|", NULL
},
296 { V('r','f'), 2, "_|", NULL
},
297 { V('r','g'), 1, "®", NULL
},
298 { V('r','k'), 1, "<FONT SIZE=+2>}</FONT>", NULL
},
299 { V('r','n'), 1, "¯", NULL
},
300 { V('r','u'), 1, "_", NULL
},
301 { V('s','c'), 1, "§", NULL
},
302 { V('s','l'), 1, "/", NULL
},
303 { V('s','q'), 2, "[]", NULL
},
304 { V('u','l'), 1, "_", NULL
},
308 /* default: print code */
311 char eqndelimopen
=0, eqndelimclose
=0;
312 char escapesym
='\\', nobreaksym
='\'', controlsym
='.', fieldsym
=0, padsym
=0;
315 int buffpos
=0, buffmax
=0;
318 int dl_set
[20]= { 0 };
320 int tabstops
[20] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
324 extern char *scan_troff(char *c
, int san
, char **result
);
326 static char **argument
=NULL
;
328 static char charb
[3];
338 timetm
=gmtime(&clock
);
339 strftime(datbuf
,500,TIMEFORMAT
, timetm
);
341 printf(signature
, datbuf
);
344 char *expand_char(int nr
)
348 if (!nr
) return NULL
;
362 char *expand_string(int nr
)
365 if (!nr
) return NULL
;
376 char outbuffer
[1024];
378 int no_newline_output
=0;
379 int newline_for_fun
=0;
380 int output_possible
=0;
383 void add_links(char *c
)
386 ** Add the links to the output.
387 ** At the moment the following are recognized:
389 ** name(*) -> ../man?/name.*
390 ** method://string -> method://string
391 ** www.host.name -> http://www.host.name
392 ** ftp.host.name -> ftp://ftp.host.name
393 ** name@host -> mailto:name@host
394 ** <name.h> -> file:/usr/include/name.h (guess)
396 ** Other possible links to add in the future:
398 ** /dir/dir/file -> file:/dir/dir/file
402 char *idtest
[6]; /* url, mailto, www, ftp, manpage */
403 out_length
+=strlen(c
);
404 /* search for (section) */
406 idtest
[0]=strstr(c
+1,"://");
407 idtest
[1]=strchr(c
+1,'@');
408 idtest
[2]=strstr(c
,"www.");
409 idtest
[3]=strstr(c
,"ftp.");
410 idtest
[4]=strchr(c
+1,'(');
411 idtest
[5]=strstr(c
+1,".h>");
412 for (i
=0; i
<6; i
++) nr
+= (idtest
[i
]!=NULL
);
416 if (idtest
[i
] && (j
<0 || idtest
[i
]<idtest
[j
])) j
=i
;
418 case 5: /* <name.h> */
422 while (g
>c
&& g
[-1]!=';') g
--;
429 printf("<A HREF=\"file:/usr/include/%s\">%s</A>>", g
,g
);
438 case 4: /* manpage */
442 if (g
&& f
-g
<6 && (isalnum(f
[-1]) || f
[-1]=='>') &&
443 ((isdigit(f
[1]) && f
[1]!='0' &&
444 (f
[2]==')' || (isalpha(f
[2]) && f
[3]==')') || f
[2]=='X')) ||
445 (f
[2]==')' && (f
[1]=='n' || f
[1]=='l')))) {
446 /* this might be a link */
448 /* skip html makeup */
449 while (h
>c
&& *h
=='>') {
450 while (h
!=c
&& *h
!='<') h
--;
454 char t
,sec
,subsec
, *e
;
458 if ((subsec
=='X' && f
[3]!=')')|| subsec
==')') subsec
='\0';
459 while (h
>c
&& (isalnum(h
[-1]) || h
[-1]=='_' ||
460 h
[-1]=='-' || h
[-1]=='.'))
468 #if LIRC_RELATIVE_PATH
470 printf("<A HREF=\"../man%c/%s.%c%c\">%s</A>",
471 sec
, h
, sec
, tolower(subsec
), h
);
473 printf("<A HREF=\"../man%c/%s.%c\">%s</A>",
475 #elif LIRC_ABSOLUTE_PATH
477 printf("<A HREF=\"file:///usr/man/man%c/%s.%c%c\">%s</A>",
478 sec
, h
, sec
, tolower(subsec
), h
);
480 printf("<A HREF=\"file:///usr/man/man%c/%s.%c\">%s</A>",
483 /* links to man pages make no sense for us */
499 while (*g
&& (isalnum(*g
) || *g
=='_' || *g
=='-' || *g
=='+' ||
507 printf("<A HREF=\"%s://%s\">%s</A>", (j
==3?"ftp":"http"),
520 while (g
>c
&& (isalnum(g
[-1]) || g
[-1]=='_' || g
[-1]=='-' ||
521 g
[-1]=='+' || g
[-1]=='.' || g
[-1]=='%')) g
--;
523 while (*h
&& (isalnum(*h
) || *h
=='_' || *h
=='-' || *h
=='+' ||
526 if (h
-f
>4 && f
-g
>1) {
532 printf("<A HREF=\"mailto:%s\">%s</A>",g
,g
);
545 while (g
>c
&& isalpha(g
[-1]) && islower(g
[-1])) g
--;
547 while (*h
&& !isspace(*h
) && *h
!='<' && *h
!='>' && *h
!='"' &&
549 if (f
-g
>2 && f
-g
<7 && h
-f
>3) {
555 printf("<A HREF=\"%s\">%s</A>", g
,g
);
569 if (idtest
[0] && idtest
[0]<c
) idtest
[0]=strstr(c
+1,"://");
570 if (idtest
[1] && idtest
[1]<c
) idtest
[1]=strchr(c
+1,'@');
571 if (idtest
[2] && idtest
[2]<c
) idtest
[2]=strstr(c
,"www.");
572 if (idtest
[3] && idtest
[3]<c
) idtest
[3]=strstr(c
,"ftp.");
573 if (idtest
[4] && idtest
[4]<c
) idtest
[4]=strchr(c
+1,'(');
574 if (idtest
[5] && idtest
[5]<c
) idtest
[5]=strstr(c
+1,".h>");
575 for (i
=0; i
<6; i
++) nr
+= (idtest
[i
]!=NULL
);
584 void out_html(char *c
)
587 if (no_newline_output
) {
591 if (!no_newline_output
) c
[i
-1]=c
[i
];
592 if (c
[i
]=='\n') no_newline_output
=0;
595 if (!no_newline_output
) c
[i
-1]=0;
599 if (buffpos
>=buffmax
) {
601 h
=realloc(buffer
, buffmax
*2);
606 buffer
[buffpos
++]=*c
++;
609 if (output_possible
) {
612 if (*c
=='\n' || obp
>1000) {
614 add_links(outbuffer
);
631 char *switchfont
[16] = { "" , FC0 FO1
, FC0 FO2
, FC0 FO3
,
632 FC1 FO0
, "" , FC1 FO2
, FC1 FO3
,
633 FC2 FO0
, FC2 FO1
, "" , FC2 FO3
,
634 FC3 FO0
, FC3 FO1
, FC3 FO2
, "" };
636 char *change_to_font(int nr
)
641 case '1': case '2': case '3': case '4': nr
=nr
-'1'; break;
642 case V('C','W'): nr
=3; break;
643 case 'L': nr
=3; break;
644 case 'B': nr
=2; break;
645 case 'I': nr
=1; break;
646 case 'P': case 'R': nr
=0; break;
647 case 0: case 1: case 2: case 3: break;
648 default: nr
=0; break;
650 i
= current_font
*4+nr
%4;
652 return switchfont
[i
];
655 static char sizebuf
[200];
657 char *change_to_size(int nr
)
661 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
662 case '7': case '8': case '9': nr
=nr
-'0'; break;
664 default: nr
=current_size
+nr
; if (nr
>9) nr
=9; if (nr
< -9) nr
=-9; break;
666 if (nr
==current_size
) return "";
669 strcat(sizebuf
, change_to_font(0));
670 if (current_size
) strcat(sizebuf
, "</FONT>");
674 strcat(sizebuf
, "<FONT SIZE=");
676 if (nr
>0) sizebuf
[l
++]='+'; else sizebuf
[l
++]='-',nr
=-nr
;
681 strcat(sizebuf
, change_to_font(i
));
688 #define SKIPEOL while (*c && *c++!='\n')
690 static int skip_escape
=0;
691 static int single_escape
=0;
693 char *scan_escape(char *c
)
698 int exoutputp
,exskipescape
;
703 case 'e': h
="\\"; curpos
++;break;
705 case ' ': h
=" ";curpos
++; break;
706 case '|': h
=""; break;
707 case '"': SKIPEOL
; c
--; h
=""; break;
712 if (!(h
=argument
[i
])) h
="";
717 if (*c
=='\\') { c
=scan_escape(c
+1); c
--;h
=""; }
724 case 'k': c
++; if (*c
=='(') c
+=2;
733 case '&': h
=""; break;
748 h
= expand_string(i
);
757 } else if (*c
!= '(')
764 if (!skip_escape
) h
=change_to_font(i
); else h
="";
769 if (*c
=='-') {j
= -1; c
++;} else if (*c
=='+') {j
=1; c
++;}
770 if (*c
=='0') c
++; else if (*c
=='\\') {
773 i
=intresult
; if (!j
) j
=1;
775 while (isdigit(*c
) && (!i
|| (!j
&& i
<4))) i
=i
*10+(*c
++)-'0';
776 if (!j
) { j
=1; if (i
) i
=i
-10; }
777 if (!skip_escape
) h
=change_to_size(i
*j
); else h
="";
784 case '+': j
=1; c
++; break;
785 case '-': j
=-1; c
++; break;
796 while (intd
&& intd
->nr
!=i
) intd
=intd
->next
;
798 intd
->val
=intd
->val
+j
*intd
->incr
;
802 case V('.','s'): intresult
=current_size
; break;
803 case V('.','f'): intresult
=current_font
; break;
804 default: intresult
=0; break;
813 exoutputp
=output_possible
;
814 exskipescape
=skip_escape
;
820 if (*c
==escapesym
) c
=scan_escape(c
+1); else c
++;
822 output_possible
=exoutputp
;
823 skip_escape
=exskipescape
;
826 case 'l': h
="<HR>"; curpos
=0;
836 exoutputp
=output_possible
;
837 exskipescape
=skip_escape
;
841 if (*c
==escapesym
) c
=scan_escape(c
+1);
843 output_possible
=exoutputp
;
844 skip_escape
=exskipescape
;
846 case 'c': no_newline_output
=1; break;
847 case '{': newline_for_fun
++; h
="";break;
848 case '}': if (newline_for_fun
) newline_for_fun
--; h
="";break;
849 case 'p': h
="<BR>\n";curpos
=0; break;
850 case 't': h
="\t";curpos
=(curpos
+8)&0xfff8; break;
851 case '<': h
="<";curpos
++; break;
852 case '>': h
=">";curpos
++; break;
853 case '\\': if (single_escape
) { c
--; break;}
854 default: b
[0]=*c
; b
[1]=0; h
=b
; curpos
++; break;
857 if (!skip_escape
) out_html(h
);
861 typedef struct TABLEITEM TABLEITEM
;
865 int size
,align
,valign
,colspan
,rowspan
,font
,vleft
,vright
,space
,width
;
869 static TABLEITEM emptyfield
= {NULL
,0,0,0,1,1,0,0,0,0,0,NULL
};
870 typedef struct TABLEROW TABLEROW
;
874 TABLEROW
*prev
, *next
;
877 static char *tableopt
[]= { "center", "expand", "box", "allbox", "doublebox",
878 "tab", "linesize", "delim", NULL
};
879 static int tableoptl
[] = { 6,6,3,6,9,3,8,5,0};
882 static void clear_table(TABLEROW
*table
)
888 while (tr1
->prev
) tr1
=tr1
->prev
;
893 if (ti1
->contents
) free(ti1
->contents
);
903 char *scan_expression(char *c
, int *result
);
905 static char *scan_format(char *c
, TABLEROW
**result
, int *maxcol
)
907 TABLEROW
*layout
, *currow
;
911 clear_table(*result
);
913 layout
= currow
=(TABLEROW
*) malloc(sizeof(TABLEROW
));
914 currow
->next
=currow
->prev
=NULL
;
915 currow
->first
=curfield
=(TABLEITEM
*) malloc(sizeof(TABLEITEM
));
916 *curfield
=emptyfield
;
917 while (*c
&& *c
!='.') {
919 case 'C': case 'c': case 'N': case 'n':
920 case 'R': case 'r': case 'A': case 'a':
921 case 'L': case 'l': case 'S': case 's':
923 if (curfield
->align
) {
924 curfield
->next
=(TABLEITEM
*)malloc(sizeof(TABLEITEM
));
925 curfield
=curfield
->next
;
926 *curfield
=emptyfield
;
928 curfield
->align
=toupper(*c
);
931 case 'i': case 'I': case 'B': case 'b':
932 curfield
->font
= toupper(*c
);
937 curfield
->font
= toupper(*c
);
939 if (!isspace(*c
)) c
++;
941 case 't': case 'T': curfield
->valign
='t'; c
++; break;
945 if (*c
=='+') { j
=1; c
++; }
946 if (*c
=='-') { j
=-1; c
++; }
947 while (isdigit(*c
)) i
=i
*10+(*c
++)-'0';
948 if (j
) curfield
->size
= i
*j
; else curfield
->size
=j
-10;
952 c
=scan_expression(c
+2,&curfield
->width
);
955 if (curfield
->align
) curfield
->vleft
++;
956 else curfield
->vright
++;
962 case '0': case '1': case '2': case '3': case '4':
963 case '5': case '6': case '7': case '8': case '9':
965 while (isdigit(*c
)) i
=i
*10+(*c
++)-'0';
969 currow
->next
=(TABLEROW
*)malloc(sizeof(TABLEROW
));
970 currow
->next
->prev
=currow
;
973 curfield
=currow
->first
=(TABLEITEM
*)malloc(sizeof(TABLEITEM
));
974 *curfield
=emptyfield
;
982 if (*c
=='.') while (*c
++!='\n');
986 curfield
=layout
->first
;
990 curfield
=curfield
->next
;
992 if (i
>*maxcol
) *maxcol
=i
;
999 TABLEROW
*next_row(TABLEROW
*tr
)
1003 if (!tr
->next
) next_row(tr
);
1006 TABLEITEM
*ti
, *ti2
;
1007 tr
->next
=(TABLEROW
*)malloc(sizeof(TABLEROW
));
1012 if (ti
) tr
->first
=ti2
=(TABLEITEM
*) malloc(sizeof(TABLEITEM
));
1013 else tr
->first
=ti2
=NULL
;
1017 if ((ti
=ti
->next
)) {
1018 ti2
->next
=(TABLEITEM
*) malloc(sizeof(TABLEITEM
));
1026 char itemreset
[20]="\\fR\\s0";
1028 char *scan_table(char *c
)
1031 int center
=0, expand
=0, box
=0, border
=0, linesize
=1;
1032 int i
,j
,maxcol
=0, finished
=0;
1033 int oldfont
, oldsize
,oldfillout
;
1035 TABLEROW
*layout
=NULL
, *currow
;
1036 TABLEITEM
*curfield
;
1039 if (*h
=='.') return c
-1;
1040 oldfont
=current_font
;
1041 oldsize
=current_size
;
1043 out_html(change_to_font(0));
1044 out_html(change_to_size(0));
1049 while (*h
&& *h
!='\n') h
++;
1051 /* scan table options */
1053 while (isspace(*c
)) c
++;
1054 for (i
=0; tableopt
[i
] && strncmp(tableopt
[i
],c
,tableoptl
[i
]);i
++);
1057 case 0: center
=1; break;
1058 case 1: expand
=1; break;
1059 case 2: box
=1; break;
1060 case 3: border
=1; break;
1061 case 4: box
=2; break;
1062 case 5: while (*c
++!='('); itemsep
=*c
++; break;
1063 case 6: while (*c
++!='('); linesize
=0;
1064 while (isdigit(*c
)) linesize
=linesize
*10+(*c
++)-'0';
1066 case 7: while (*c
!=')') c
++;
1074 c
=scan_format(c
,&layout
, &maxcol
);
1077 curfield
=layout
->first
;
1082 if ((*c
=='_' || *c
=='=') && (c
[1]==itemsep
|| c
[1]=='\n')) {
1083 if (c
[-1]=='\n' && c
[1]=='\n') {
1085 currow
->prev
->next
=(TABLEROW
*) malloc(sizeof(TABLEROW
));
1086 currow
->prev
->next
->next
=currow
;
1087 currow
->prev
->next
->prev
=currow
->prev
;
1088 currow
->prev
=currow
->prev
->next
;
1090 currow
->prev
=layout
=(TABLEROW
*) malloc(sizeof(TABLEROW
));
1091 currow
->prev
->prev
=NULL
;
1092 currow
->prev
->next
=currow
;
1094 curfield
=currow
->prev
->first
=
1095 (TABLEITEM
*) malloc(sizeof(TABLEITEM
));
1096 *curfield
=emptyfield
;
1098 curfield
->colspan
=maxcol
;
1099 curfield
=currow
->first
;
1105 curfield
=curfield
->next
;
1106 } while (curfield
&& curfield
->align
=='S');
1109 currow
=next_row(currow
);
1110 curfield
=currow
->first
;
1114 } else if (*c
=='T' && c
[1]=='{') {
1121 scan_troff(itemreset
, 0,&g
);
1125 curfield
->contents
=g
;
1127 curfield
=curfield
->next
;
1128 } while (curfield
&& curfield
->align
=='S');
1132 currow
=next_row(currow
);
1133 curfield
=currow
->first
;
1135 } else if (*c
=='.' && c
[1]=='T' && c
[2]=='&' && c
[-1]=='\n') {
1139 currow
=currow
->prev
;
1141 c
=scan_format(c
,&hr
, &i
);
1146 curfield
=currow
->first
;
1147 } else if (*c
=='.' && c
[1]=='T' && c
[2]=='E' && c
[-1]=='\n') {
1151 currow
->prev
->next
=NULL
;
1153 clear_table(currow
);
1154 } else if (*c
=='.' && c
[-1]=='\n' && !isdigit(c
[1])) {
1155 /* skip troff request inside table (usually only .sp ) */
1159 while (*c
&& (*c
!=itemsep
|| c
[-1]=='\\') &&
1160 (*c
!='\n' || c
[-1]=='\\')) c
++;
1162 if (*c
==itemsep
) {i
=1; *c
='\n'; }
1163 if (h
[0]=='\\' && h
[2]=='\n' &&
1164 (h
[1]=='_' || h
[1]=='^')) {
1166 curfield
->align
=h
[1];
1168 curfield
=curfield
->next
;
1169 } while (curfield
&& curfield
->align
=='S');
1174 h
=scan_troff(h
,1,&g
);
1175 scan_troff(itemreset
,0,&g
);
1177 curfield
->contents
=g
;
1179 curfield
=curfield
->next
;
1180 } while (curfield
&& curfield
->align
=='S');
1181 } else if (g
) free(g
);
1186 currow
=next_row(currow
);
1187 curfield
=currow
->first
;
1191 /* calculate colspan and rowspan */
1193 while (currow
->next
) currow
=currow
->next
;
1195 TABLEITEM
*ti
, *ti1
=NULL
, *ti2
=NULL
;
1197 if (currow
->prev
) ti1
=currow
->prev
->first
;
1199 switch (ti
->align
) {
1203 if (ti2
->rowspan
<ti
->rowspan
) ti2
->rowspan
=ti
->rowspan
;
1207 if (ti1
) ti1
->rowspan
++;
1213 } while (ti2
&& curfield
->align
=='S');
1218 if (ti1
) ti1
=ti1
->next
;
1220 currow
=currow
->prev
;
1222 /* produce html output */
1223 if (center
) out_html("<CENTER>");
1224 if (box
==2) out_html("<TABLE BORDER><TR><TD>");
1226 if (box
|| border
) {
1227 out_html(" BORDER");
1228 if (!border
) out_html("><TR><TD><TABLE");
1229 if (expand
) out_html(" WIDTH=100%");
1235 out_html("<TR VALIGN=top>");
1236 curfield
=currow
->first
;
1238 if (curfield
->align
!='S' && curfield
->align
!='^') {
1240 switch (curfield
->align
) {
1244 out_html(" ALIGN=right");
1247 out_html(" ALIGN=center");
1251 if (!curfield
->valign
&& curfield
->rowspan
>1)
1252 out_html(" VALIGN=center");
1253 if (curfield
->colspan
>1) {
1255 out_html(" COLSPAN=");
1256 sprintf(buf
, "%i", curfield
->colspan
);
1259 if (curfield
->rowspan
>1) {
1261 out_html(" ROWSPAN=");
1262 sprintf(buf
, "%i", curfield
->rowspan
);
1265 j
=j
+curfield
->colspan
;
1267 if (curfield
->size
) out_html(change_to_size(curfield
->size
));
1268 if (curfield
->font
) out_html(change_to_font(curfield
->font
));
1269 switch (curfield
->align
) {
1270 case '=': out_html("<HR><HR>"); break;
1271 case '_': out_html("<HR>"); break;
1273 if (curfield
->contents
) out_html(curfield
->contents
);
1276 if (curfield
->space
)
1277 for (i
=0; i
<curfield
->space
;i
++) out_html(" ");
1278 if (curfield
->font
) out_html(change_to_font(0));
1279 if (curfield
->size
) out_html(change_to_size(0));
1280 if (j
>=maxcol
&& curfield
->align
>'@' && curfield
->align
!='_')
1284 curfield
=curfield
->next
;
1286 out_html("</TR>\n");
1287 currow
=currow
->next
;
1289 if (box
&& !border
) out_html("</TABLE>");
1290 out_html("</TABLE>");
1291 if (box
==2) out_html("</TABLE>");
1292 if (center
) out_html("</CENTER>\n");
1293 else out_html("\n");
1294 if (!oldfillout
) out_html("<PRE>");
1296 out_html(change_to_size(oldsize
));
1297 out_html(change_to_font(oldfont
));
1301 char *scan_expression(char *c
, int *result
)
1303 int value
=0,value2
,sign
=1,opex
=0;
1307 c
=scan_expression(c
+1, &value
);
1309 } else if (*c
=='n') {
1312 } else if (*c
=='t') {
1315 } else if (*c
=='\'' || *c
=='"' || *c
<' ' || (*c
=='\\' && c
[1]=='(')) {
1316 /* ?string1?string2?
1317 ** test if string1 equals string2.
1319 char *st1
=NULL
, *st2
=NULL
, *h
;
1329 while (*c
!= sep
&& (!tcmp
|| strncmp(c
,tcmp
,4))) c
++;
1331 scan_troff(h
, 1, &st1
);
1336 while (*c
!=sep
&& (!tcmp
|| strncmp(c
,tcmp
,4))) c
++;
1338 scan_troff(h
,1,&st2
);
1340 if (!st1
&& !st2
) value
=1;
1341 else if (!st1
|| !st2
) value
=0;
1342 else value
=(!strcmp(st1
, st2
));
1348 while (*c
&& !isspace(*c
) && *c
!=')') {
1352 c
=scan_expression(c
+1, &value2
);
1361 case '8': case '9': {
1364 while (isdigit(*c
)) value2
=value2
*10+((*c
++)-'0');
1367 while (isdigit(*c
)) {
1368 num
=num
*10+((*c
++)-'0');
1373 /* scale indicator */
1375 case 'i': /* inch -> 10pt */
1376 value2
=value2
*10+(num
*10+denum
/2)/denum
;
1384 value2
=value2
+(num
+denum
/2)/denum
;
1391 value2
=intresult
*sign
;
1392 if (isalpha(*c
)) c
++; /* scale indicator */
1396 if (oper
) { sign
=-1; c
++; break; }
1406 if (c
[1]=='=') oper
=(*c
++) +16; else oper
=*c
;
1409 default: c
++; break;
1414 case 'c': value
=value2
; break;
1415 case '-': value
=value
-value2
; break;
1416 case '+': value
=value
+value2
; break;
1417 case '*': value
=value
*value2
; break;
1418 case '/': if (value2
) value
=value
/value2
; break;
1419 case '%': if (value2
) value
=value
%value2
; break;
1420 case '<': value
=(value
<value2
); break;
1421 case '>': value
=(value
>value2
); break;
1422 case '>'+16: value
=(value
>=value2
); break;
1423 case '<'+16: value
=(value
<=value2
); break;
1424 case '=': case '='+16: value
=(value
==value2
); break;
1425 case '&': value
= (value
&& value2
); break;
1426 case ':': value
= (value
|| value2
); break;
1427 default: fprintf(stderr
, "Unknown operator %c.\n", oper
);
1438 void trans_char(char *c
, char s
, char t
)
1442 while (*sl
!='\n' || slash
) {
1453 char *fill_words(char *c
, char *words
[], int *n
)
1460 while (*sl
&& (*sl
!='\n' || slash
)) {
1464 skipspace
=!skipspace
;
1465 } else if (*sl
==escapesym
)
1467 else if ((*sl
==' ' || *sl
=='\t') && !skipspace
) {
1469 if (words
[*n
]!=sl
) (*n
)++;
1476 if (words
[*n
]!=sl
) (*n
)++;
1478 while (*sl
&& *sl
!='\n') sl
++;
1486 if (sl
!=words
[*n
]) (*n
)++;
1490 char *abbrev_list
[] = {
1491 "GSBG", "Getting Started ",
1492 "SUBG", "Customizing SunOS",
1493 "SHBG", "Basic Troubleshooting",
1494 "SVBG", "SunView User's Guide",
1495 "MMBG", "Mail and Messages",
1496 "DMBG", "Doing More with SunOS",
1497 "UNBG", "Using the Network",
1498 "GDBG", "Games, Demos & Other Pursuits",
1499 "CHANGE", "SunOS 4.1 Release Manual",
1500 "INSTALL", "Installing SunOS 4.1",
1501 "ADMIN", "System and Network Administration",
1502 "SECUR", "Security Features Guide",
1503 "PROM", "PROM User's Manual",
1504 "DIAG", "Sun System Diagnostics",
1505 "SUNDIAG", "Sundiag User's Guide",
1506 "MANPAGES", "SunOS Reference Manual",
1507 "REFMAN", "SunOS Reference Manual",
1508 "SSI", "Sun System Introduction",
1509 "SSO", "System Services Overview",
1510 "TEXT", "Editing Text Files",
1511 "DOCS", "Formatting Documents",
1512 "TROFF", "Using <B>nroff</B> and <B>troff</B>",
1513 "INDEX", "Global Index",
1514 "CPG", "C Programmer's Guide",
1515 "CREF", "C Reference Manual",
1516 "ASSY", "Assembly Language Reference",
1517 "PUL", "Programming Utilities and Libraries",
1518 "DEBUG", "Debugging Tools",
1519 "NETP", "Network Programming",
1520 "DRIVER", "Writing Device Drivers",
1521 "STREAMS", "STREAMS Programming",
1522 "SBDK", "SBus Developer's Kit",
1523 "WDDS", "Writing Device Drivers for the SBus",
1524 "FPOINT", "Floating-Point Programmer's Guide",
1525 "SVPG", "SunView 1 Programmer's Guide",
1526 "SVSPG", "SunView 1 System Programmer's Guide",
1527 "PIXRCT", "Pixrect Reference Manual",
1528 "CGI", "SunCGI Reference Manual",
1529 "CORE", "SunCore Reference Manual",
1530 "4ASSY", "Sun-4 Assembly Language Reference",
1531 "SARCH", "<FONT SIZE=-1>SPARC</FONT> Architecture Manual",
1532 "KR", "The C Programming Language",
1535 char *lookup_abbrev(char *c
)
1540 while (abbrev_list
[i
] && strcmp(c
,abbrev_list
[i
])) i
=i
+2;
1541 if (abbrev_list
[i
]) return abbrev_list
[i
+1];
1545 char *section_list
[] = {
1546 "1", "User Commands ",
1547 "1C", "User Commands",
1548 "1G", "User Commands",
1549 "1S", "User Commands",
1550 "1V", "User Commands ",
1551 "2", "System Calls",
1552 "2V", "System Calls",
1553 "3", "C Library Functions",
1554 "3C", "Compatibility Functions",
1555 "3F", "Fortran Library Routines",
1556 "3K", "Kernel VM Library Functions",
1557 "3L", "Lightweight Processes Library",
1558 "3M", "Mathematical Library",
1559 "3N", "Network Functions",
1560 "3R", "RPC Services Library",
1561 "3S", "Standard I/O Functions",
1562 "3V", "C Library Functions",
1563 "3X", "Miscellaneous Library Functions",
1564 "4", "Devices and Network Interfaces",
1565 "4F", "Protocol Families",
1566 "4I", "Devices and Network Interfaces",
1567 "4M", "Devices and Network Interfaces",
1568 "4N", "Devices and Network Interfaces",
1570 "4S", "Devices and Network Interfaces",
1571 "4V", "Devices and Network Interfaces",
1572 "5", "File Formats",
1573 "5V", "File Formats",
1574 "6", "Games and Demos",
1575 "7", "Environments, Tables, and Troff Macros",
1576 "7V", "Environments, Tables, and Troff Macros",
1577 "8", "Maintenance Commands",
1578 "8C", "Maintenance Commands",
1579 "8S", "Maintenance Commands",
1580 "8V", "Maintenance Commands",
1581 "L", "Local Commands",
1583 "1", "User Commands",
1584 "1B", "SunOS/BSD Compatibility Package Commands",
1585 "1b", "SunOS/BSD Compatibility Package Commands",
1586 "1C", "Communication Commands ",
1587 "1c", "Communication Commands",
1588 "1F", "FMLI Commands ",
1589 "1f", "FMLI Commands",
1590 "1G", "Graphics and CAD Commands ",
1591 "1g", "Graphics and CAD Commands ",
1592 "1M", "Maintenance Commands",
1593 "1m", "Maintenance Commands",
1594 "1S", "SunOS Specific Commands",
1595 "1s", "SunOS Specific Commands",
1596 "2", "System Calls",
1597 "3", "C Library Functions",
1598 "3B", "SunOS/BSD Compatibility Library Functions",
1599 "3b", "SunOS/BSD Compatibility Library Functions",
1600 "3C", "C Library Functions",
1601 "3c", "C Library Functions",
1602 "3E", "C Library Functions",
1603 "3e", "C Library Functions",
1604 "3F", "Fortran Library Routines",
1605 "3f", "Fortran Library Routines",
1606 "3G", "C Library Functions",
1607 "3g", "C Library Functions",
1608 "3I", "Wide Character Functions",
1609 "3i", "Wide Character Functions",
1610 "3K", "Kernel VM Library Functions",
1611 "3k", "Kernel VM Library Functions",
1612 "3L", "Lightweight Processes Library",
1613 "3l", "Lightweight Processes Library",
1614 "3M", "Mathematical Library",
1615 "3m", "Mathematical Library",
1616 "3N", "Network Functions",
1617 "3n", "Network Functions",
1618 "3R", "Realtime Library",
1619 "3r", "Realtime Library",
1620 "3S", "Standard I/O Functions",
1621 "3s", "Standard I/O Functions",
1622 "3T", "Threads Library",
1623 "3t", "Threads Library",
1624 "3W", "C Library Functions",
1625 "3w", "C Library Functions",
1626 "3X", "Miscellaneous Library Functions",
1627 "3x", "Miscellaneous Library Functions",
1628 "4", "File Formats",
1629 "4B", "SunOS/BSD Compatibility Package File Formats",
1630 "4b", "SunOS/BSD Compatibility Package File Formats",
1631 "5", "Headers, Tables, and Macros",
1632 "6", "Games and Demos",
1633 "7", "Special Files",
1634 "7B", "SunOS/BSD Compatibility Special Files",
1635 "7b", "SunOS/BSD Compatibility Special Files",
1636 "8", "Maintenance Procedures",
1637 "8C", "Maintenance Procedures",
1638 "8c", "Maintenance Procedures",
1639 "8S", "Maintenance Procedures",
1640 "8s", "Maintenance Procedures",
1642 "9E", "DDI and DKI Driver Entry Points",
1643 "9e", "DDI and DKI Driver Entry Points",
1644 "9F", "DDI and DKI Kernel Functions",
1645 "9f", "DDI and DKI Kernel Functions",
1646 "9S", "DDI and DKI Data Structures",
1647 "9s", "DDI and DKI Data Structures",
1648 "L", "Local Commands",
1650 NULL
, "Misc. Reference Manual Pages",
1654 char *section_name(char *c
)
1659 while (section_list
[i
] && strcmp(c
,section_list
[i
])) i
=i
+2;
1660 if (section_list
[i
+1]) return section_list
[i
+1];
1667 char label
[5]="lbAA";
1669 void add_to_index(int level
, char *item
)
1677 if (level
!= subs
) {
1679 strcpy(manidx
+mip
, "</DL>\n");
1682 strcpy(manidx
+mip
, "<DL>\n");
1687 scan_troff(item
, 1, &c
);
1688 sprintf(manidx
+mip
, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label
, c
);
1690 while (manidx
[mip
]) mip
++;
1693 char *skip_till_newline(char *c
)
1697 while ((*c
&& *c
!='\n') || (lvl
>0)) {
1700 if (*c
=='}') lvl
--; else if (*c
=='{') lvl
++;
1705 if (lvl
<0 && newline_for_fun
) {
1706 newline_for_fun
= newline_for_fun
+lvl
;
1707 if (newline_for_fun
<0) newline_for_fun
=0;
1714 char *scan_request(char *c
)
1722 while (*c
==' ' || *c
=='\t') c
++;
1723 if (c
[0]=='\n') return c
+1;
1724 if (c
[1]=='\n') j
=1; else j
=2;
1725 while (c
[j
]==' ' || c
[j
]=='\t') j
++;
1726 if (c
[0]==escapesym
) {
1727 /* some pages use .\" .\$1 .\} */
1728 /* .\$1 is too difficult/stuppid */
1729 if (c
[1]=='$') c
=skip_till_newline(c
);
1731 c
= scan_escape(c
+1);
1737 while (*h
&& *h
!='\n') h
++;
1739 if (scaninbuff
&& buffpos
) {
1740 buffer
[buffpos
]='\0';
1741 printf("%s\n", buffer
);
1743 fprintf(stderr
, "%s\n", c
+2);
1751 if (*c
=='\n') { c
++;break; }
1752 while (*c
&& *c
!='\n') c
++;
1755 while (*c
&& strncmp(c
,".di",3)) while (*c
&& *c
++!='\n');
1758 while (de
&& de
->nr
!=i
) de
=de
->next
;
1760 de
=(STRDEF
*) malloc(sizeof(STRDEF
));
1767 if (de
->st
) free(de
->st
);
1771 scan_troff(h
,0,&de
->st
);
1773 while (*c
&& *c
++!='\n');
1781 int oldcurpos
=curpos
;
1785 while (c
[j
] && c
[j
]!='\n') j
++;
1786 if (j
<3) { c
=c
+j
; break; }
1787 if (c
[1]==' ') c
=c
+1; else c
=c
+2;
1788 while (isspace(*c
)) c
++;
1791 while (de
&& de
->nr
!= i
) de
=de
->next
;
1796 de
=(STRDEF
*) malloc(sizeof(STRDEF
));
1803 c
=scan_troff(c
, 1, &h
);
1809 c
=scan_troff(c
, 1, &h
);
1814 c
=scan_troff(c
,1,&de
->st
);
1822 if (still_dd
) out_html("<DD>");
1823 else out_html("<BR>\n");
1826 if (c
[0]==escapesym
) { c
=scan_escape(c
+1); }
1827 c
=skip_till_newline(c
);break;
1830 if (*c
!='\n') { nobreaksym
=*c
; }
1831 else nobreaksym
='\'';
1832 c
=skip_till_newline(c
);
1836 if (*c
!='\n') { controlsym
=*c
; }
1837 else controlsym
='.';
1838 c
=skip_till_newline(c
);
1842 if (*c
=='\n') { i
=1; }
1845 while ('0'<=*c
&& *c
<='9') {
1850 c
=skip_till_newline(c
);
1851 /* center next i lines */
1853 out_html("<CENTER>\n");
1856 c
=scan_troff(c
,1, &line
);
1857 if (line
&& strncmp(line
, "<BR>", 4)) {
1863 out_html("</CENTER>\n");
1869 if (*c
!='\n') { escapesym
=*c
; }
1870 else escapesym
='\\';
1872 c
=skip_till_newline(c
);
1875 c
=skip_till_newline(c
);
1883 fieldsym
=padsym
='\0';
1888 c
=skip_till_newline(c
);
1892 out_html(change_to_font(0));
1893 out_html(change_to_size('0'));
1894 out_html("</PRE>\n");
1898 c
=skip_till_newline(c
);
1903 out_html(change_to_font(0));
1905 if (*c
==escapesym
) {
1907 c
=scan_expression(c
, &fn
);
1909 out_html(change_to_font(fn
));
1911 out_html(change_to_font(*c
));
1915 c
=skip_till_newline(c
);
1918 /* .el anything : else part of if else */
1922 c
=scan_troff(c
,1,NULL
);
1924 c
=skip_till_newline(c
+j
);
1927 /* .ie c anything : then part of if else */
1933 * .if 'string1'string2' anything
1934 * .if !'string1'string2' anything
1937 c
=scan_expression(c
, &i
);
1942 c
=scan_troff(c
,1,NULL
);
1944 c
=skip_till_newline(c
);
1948 char *endwith
="..\n";
1954 while (*c
!='\n') c
++,i
++;
1957 while (*c
&& strncmp(c
,endwith
,i
)) while (*c
++!='\n');
1963 out_html(change_to_font(0));
1964 out_html(change_to_size('0'));
1965 out_html("<PRE>\n");
1969 c
=skip_till_newline(c
);
1974 out_html(change_to_size('0'));
1977 if (*c
=='-') { j
= -1;c
++; } else if (*c
=='+') { j
=1;c
++;}
1978 c
=scan_expression(c
, &i
);
1979 if (!j
) { j
=1; if (i
>5) i
=i
-10; }
1980 out_html(change_to_size(i
*j
));
1982 c
=skip_till_newline(c
);
1986 if (fillout
) out_html("<P>"); else {
1991 c
=skip_till_newline(c
);
2009 while (*c
!='\n') c
++;
2011 scan_troff(h
,1, &name
);
2012 if (name
[3]=='/') h
=name
+3; else h
=name
;
2013 if (stat(h
, &stbuf
)!=-1) l
=stbuf
.st_size
;
2014 buf
= (char*) malloc((l
+4)*sizeof(char));
2018 t
=strrchr(fname
, '/');
2020 fprintf(stderr
, "ln -s %s.html %s.html\n", h
, t
);
2021 s
=strrchr(t
, '.');if (!s
) s
=t
;
2022 printf("<HTML><HEAD><TITLE> Manpage of %s</TITLE>\n"
2024 "See the manpage for <A HREF=\"%s.html\">%s</A>.\n"
2030 /* this works alright, except for section 3 */
2032 if (!f
|| !buf
|| !l
)
2033 fprintf(stderr
, "Unable to open or read file %s.\n",
2036 i
=fread(buf
+1,1,l
,f
);
2039 buf
[l
+1]=buf
[l
+2]='\0';
2040 scan_troff(buf
+1,0,NULL
);
2051 sl
=scan_expression(c
, &tabstops
[j
]);
2052 if (*c
=='-' || *c
=='+') tabstops
[j
]+=tabstops
[j
-1];
2054 while (*c
==' ' || *c
=='\t') c
++;
2061 /*while (itemdepth || dl_set[itemdepth]) {
2062 out_html("</DL>\n");
2063 if (dl_set[itemdepth]) dl_set[itemdepth]=0;
2068 c
=scan_expression(c
, &j
);
2069 for (i
=0; i
<j
; i
++) out_html(" ");
2071 c
=skip_till_newline(c
);
2076 while (*c
!='\n') c
++;
2078 fprintf(stderr
,"%s\n", h
);
2085 /* parse one line in a certain font */
2086 out_html(change_to_font(*c
));
2087 trans_char(c
,'"','\a');
2090 c
=scan_troff(c
, 1, NULL
);
2091 out_html(change_to_font('R'));
2093 if (fillout
) curpos
++; else curpos
=0;
2095 case V('O','P'): /* groff manpages use this construction */
2096 /* .OP a b : [ <B>a</B> <I>b</I> ] */
2099 out_html(change_to_font('R'));
2109 char font
[2] = { c
[0], c
[1] };
2112 sl
=fill_words(c
, wordlist
, &words
);
2114 /* .BR name (section)
2115 ** indicates a link. It will be added in the output routine.
2117 for (i
=0; i
<words
; i
++) {
2118 if (mode
) { out_html(" "); curpos
++; }
2119 wordlist
[i
][-1]=' ';
2120 out_html(change_to_font(font
[i
&1]));
2121 scan_troff(wordlist
[i
],1,NULL
);
2123 out_html(change_to_font('R'));
2124 if (mode
) { out_html(" ]"); curpos
++;}
2125 out_html(NEWLINE
); if (!fillout
) curpos
=0; else curpos
++;
2129 for (j
=0;j
<20; j
++) tabstops
[j
]=(j
+1)*8;
2131 c
=skip_till_newline(c
); break;
2133 sl
=fill_words(c
+j
, wordlist
, &words
);
2135 if (!dl_set
[itemdepth
]) {
2136 out_html("<DL COMPACT>\n");
2137 dl_set
[itemdepth
]=1;
2141 scan_troff(wordlist
[0], 1,NULL
);
2147 if (!dl_set
[itemdepth
]) {
2148 out_html("<DL COMPACT>\n");
2149 dl_set
[itemdepth
]=1;
2152 c
=skip_till_newline(c
);
2153 /* somewhere a definition ends with '.TP' */
2154 if (!*c
) still_dd
=1; else {
2155 c
=scan_troff(c
,1,NULL
);
2162 sl
= fill_words(c
+j
, wordlist
, &words
);
2165 while (idxlabel
[j
]=='Z') idxlabel
[j
--]='A';
2168 fprintf(idxfile
, "%s@%s@", fname
, idxlabel
);
2169 for (j
=0; j
<words
; j
++) {
2171 scan_troff(wordlist
[j
], 1, &h
);
2172 fprintf(idxfile
, "_\b@%s", h
);
2175 fprintf(idxfile
,"\n");
2177 out_html("<A NAME=\"");
2179 /* this will not work in mosaic (due to a bug).
2180 ** Adding ' ' between '>' and '<' solves it, but creates
2181 ** some space. A normal space does not work.
2183 out_html("\"></A>");
2187 if (dl_set
[itemdepth
]) {
2188 out_html("</DL>\n");
2189 dl_set
[itemdepth
]=0;
2191 if (fillout
) out_html("<P>\n"); else {
2196 c
=skip_till_newline(c
);
2199 if (!dl_set
[itemdepth
]) {
2200 out_html("<DL COMPACT>");
2201 dl_set
[itemdepth
]=1;
2205 c
=skip_till_newline(c
);
2208 case V('P','D'): c
=skip_till_newline(c
); break;
2210 sl
=fill_words(c
+j
, wordlist
, &words
);
2212 if (words
>0) scan_expression(wordlist
[0], &j
);
2215 dl_set
[itemdepth
]=0;
2216 out_html("<DL COMPACT><DT><DD>");
2217 c
=skip_till_newline(c
);
2223 if (dl_set
[itemdepth
]) out_html("</DL>");
2224 out_html("</DL>\n");
2227 c
=skip_till_newline(c
);
2231 out_html(change_to_size(-1));
2232 out_html(change_to_font('B'));
2233 c
=scan_troff(c
+j
, 1, NULL
);
2234 out_html(change_to_font('R'));
2235 out_html(change_to_size('0'));
2240 out_html(change_to_size(-1));
2241 trans_char(c
,'"','\a');
2242 c
=scan_troff(c
,1,NULL
);
2243 out_html(change_to_size('0'));
2250 while (itemdepth
|| dl_set
[itemdepth
]) {
2251 out_html("</DL>\n");
2252 if (dl_set
[itemdepth
]) dl_set
[itemdepth
]=0;
2255 out_html(change_to_font(0));
2256 out_html(change_to_size(0));
2261 trans_char(c
,'"', '\a');
2262 add_to_index(mode
, c
);
2263 out_html("<A NAME=\"");
2265 /* for mosaic users */
2266 if (mode
) out_html("\"> </A>\n<H3>");
2267 else out_html("\"> </A>\n<H2>");
2268 c
=scan_troff(c
,1,NULL
);
2269 if (mode
) out_html("</H3>\n");
2270 else out_html("</H2>\n");
2277 if (!output_possible
) {
2278 sl
= fill_words(c
+j
, wordlist
, &words
);
2280 for (i
=1; i
<words
; i
++) wordlist
[i
][-1]='\0';
2283 out_html("<HTML><HEAD><TITLE>Manpage of ");
2284 out_html(wordlist
[0]);
2285 out_html("</TITLE>\n</HEAD><BODY>\n<H1>");
2286 out_html(wordlist
[0]);
2287 out_html("</H1>\nSection: ");
2288 if (words
>4) out_html(wordlist
[4]);
2290 out_html(section_name(wordlist
[1]));
2292 out_html(wordlist
[1]);
2294 out_html(")<BR>Updated: ");
2295 scan_troff(wordlist
[2], 1, NULL
);
2296 } else out_html(")");
2297 out_html("<BR><A HREF=\"#index\">Index</A>\n");
2302 } else c
=skip_till_newline(c
);
2306 sl
=fill_words(c
+j
, wordlist
, &words
);
2308 out_html(change_to_font('I'));
2309 if (words
>1) wordlist
[1][-1]='\0';
2310 c
=lookup_abbrev(wordlist
[0]);
2313 out_html(change_to_font('R'));
2315 out_html(wordlist
[1]);
2320 /* .rm xx : Remove request, macro or string */
2322 /* .rn xx yy : Rename request, macro or string xx to yy */
2328 while (isspace(*c
) && *c
!='\n') c
++;
2330 while (*c
&& *c
!='\n') c
++;
2333 while (de
&& de
->nr
!=j
) de
=de
->next
;
2335 if (de
->st
) free(de
->st
);
2339 while (de
&& de
->nr
!=i
) de
=de
->next
;
2344 /* .nx filename : next file. */
2346 /* .in +-N : Indent */
2347 c
=skip_till_newline(c
);
2350 /* .nr R +-N M: define and set number register R by +-N;
2351 ** auto-increment by M
2359 while (intd
&& intd
->nr
!=i
) intd
=intd
->next
;
2361 intd
= (INTDEF
*) malloc(sizeof(INTDEF
));
2368 while (*c
==' ' || *c
=='\t') c
++;
2369 c
=scan_expression(c
,&intd
->val
);
2371 while (*c
==' ' || *c
=='\t') c
++;
2372 c
=scan_expression(c
,&intd
->incr
);
2374 c
=skip_till_newline(c
);
2378 /* .am xx yy : append to a macro. */
2379 /* define or handle as .ig yy */
2382 /* .de xx yy : define or redefine macro xx; end at .yy (..) */
2383 /* define or handle as .ig yy */
2388 sl
=fill_words(c
, wordlist
, &words
);
2390 if (words
==1) wordlist
[1]=".."; else {
2397 while (*c
&& strncmp(c
,wordlist
[1],j
)) c
=skip_till_newline(c
);
2399 while (de
&& de
->nr
!= i
) de
=de
->next
;
2400 if (mode
&& de
) olen
=strlen(de
->st
);
2402 h
= (char*) malloc((j
*2+4)*sizeof(char));
2404 for (j
=0; j
<olen
; j
++)
2406 if (!j
|| h
[j
-1]!='\n')
2409 if (sl
[0]=='\\' && sl
[1]=='\\') {
2417 if (de
->st
) free(de
->st
);
2420 de
= (STRDEF
*) malloc(sizeof(STRDEF
));
2428 c
=skip_till_newline(c
);
2431 /* search macro database of self-defined macros */
2433 while (owndef
&& owndef
->nr
!=i
) owndef
=owndef
->next
;
2438 sl
=fill_words(c
+j
, wordlist
, &words
);
2441 for (i
=1;i
<words
; i
++) wordlist
[i
][-1]='\0';
2442 for (i
=0; i
<words
; i
++) {
2444 scan_troff(wordlist
[i
],1,&h
);
2447 for (i
=words
;i
<20; i
++) wordlist
[i
]=NULL
;
2448 deflen
= strlen(owndef
->st
);
2449 owndef
->st
[deflen
+1]='a';
2450 for (i
=0; (owndef
->st
[deflen
+2+i
]=owndef
->st
[i
]); i
++);
2451 oldargument
=argument
;
2453 onff
=newline_for_fun
;
2454 scan_troff(owndef
->st
+deflen
+2, 0, NULL
);
2455 newline_for_fun
=onff
;
2456 argument
=oldargument
;
2457 for (i
=0; i
<words
; i
++) if (wordlist
[i
]) free(wordlist
[i
]);
2460 c
=skip_till_newline(c
);
2464 if (fillout
) { out_html(NEWLINE
); curpos
++; }
2473 static int contained_tab
=0;
2475 char *scan_troff(char *c
, int san
, char **result
)
2476 { /* san : stop at newline */
2480 #define FLUSHIBP if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
2482 int exbuffpos
, exbuffmax
, exscaninbuff
, exnewline_for_fun
;
2488 exnewline_for_fun
=newline_for_fun
;
2489 exscaninbuff
=scaninbuff
;
2494 buffpos
=strlen(buffer
);
2497 buffer
=(char *) malloc(1000*sizeof(char));
2504 /* start scanning */
2505 while (*h
&& (!san
|| newline_for_fun
|| *h
!='\n')) {
2506 if (*h
==escapesym
) {
2510 } else if (*h
==controlsym
&& h
[-1]=='\n') {
2513 h
= scan_request(h
);
2514 if (san
&& h
[-1]=='\n') h
--;
2515 } else if (*h
==nobreaksym
&& h
[-1]=='\n') {
2518 h
= scan_request(h
);
2519 if (san
&& h
[-1]=='\n') h
--;
2521 if (h
[-1]=='\n' && still_dd
&& isalnum(*h
)) {
2522 /* sometimes a .HP request is not followed by a .br request */
2561 if (h
[-1]=='\n' && fillout
) {
2566 if (contained_tab
&& fillout
) {
2575 intbuff
[ibp
++]='\n';
2582 /* like a typewriter, not like TeX */
2583 tabstops
[19]=curpos
+1;
2584 while (curtab
<maxtstop
&& tabstops
[curtab
]<=curpos
)
2586 if (curtab
<maxtstop
) {
2588 while (curpos
<tabstops
[curtab
]) {
2590 if (ibp
>480) { FLUSHIBP
; }
2595 while (curpos
<tabstops
[curtab
]) {
2605 if (*h
==' ' && (h
[-1]=='\n' || usenbsp
)) {
2607 if (!usenbsp
&& fillout
) {
2612 if (usenbsp
) out_html(" "); else intbuff
[ibp
++]=' ';
2613 } else if (*h
>31 && *h
<127) intbuff
[ibp
++]=*h
;
2614 else if (((unsigned char)(*h
))>127) {
2617 intbuff
[ibp
++]='0'+((unsigned char)(*h
))/100;
2618 intbuff
[ibp
++]='0'+(((unsigned char)(*h
))%100)/10;
2619 intbuff
[ibp
++]='0'+((unsigned char)(*h
))%10;
2625 if (ibp
>480) FLUSHIBP
;
2630 if (buffer
) buffer
[buffpos
]='\0';
2632 newline_for_fun
=exnewline_for_fun
;
2638 scaninbuff
=exscaninbuff
;
2643 char *sectionname
=NULL
;
2644 STRDEF
*foundpages
=NULL
;
2646 int search_manpath_all(char *name
)
2655 strcpy(cmpbuf
,name
);
2659 for (i
=0; manpath
[i
]; i
++) {
2660 strcpy(smfbuf
, manpath
[i
]);
2662 strcpy(smfbuf
+l
, "man");
2665 for (j
=0; sections
[j
]; j
++) {
2666 smfbuf
[l
]=sections
[j
];
2667 cmpbuf
[n
]=sections
[j
];
2668 if ((dr
=opendir(smfbuf
))) {
2669 while ((de
=readdir(dr
))) {
2670 if (!strncmp(de
->d_name
, cmpbuf
, n
+1)) {
2673 h
->next
=(STRDEF
*) malloc(sizeof(STRDEF
));
2676 h
=foundpages
=(STRDEF
*) malloc(sizeof(STRDEF
));
2678 stlen
=strlen(de
->d_name
)+1;
2679 h
->st
=(char*) malloc(stlen
*sizeof(char));
2681 strcpy(h
->st
, de
->d_name
);
2692 int search_manpath_section(char *name
, char* section
)
2701 if (!section
) return search_manpath_all(name
);
2703 while (sections
[j
] && sections
[j
]!=section
[0]) j
++;
2704 if (!sections
[j
]) return search_manpath_all(name
);
2705 strcpy(cmpbuf
,name
);
2708 cmpbuf
[n
++]=section
[0];
2710 for (i
=0; manpath
[i
]; i
++) {
2711 strcpy(smfbuf
, manpath
[i
]);
2713 strcpy(smfbuf
+l
, "man");
2715 smfbuf
[l
]=section
[0];
2717 if ((dr
=opendir(smfbuf
))) {
2718 while ((de
=readdir(dr
))) {
2719 if (!strncmp(de
->d_name
, cmpbuf
, n
)) {
2722 h
->next
=(STRDEF
*) malloc(sizeof(STRDEF
));
2725 h
=foundpages
=(STRDEF
*) malloc(sizeof(STRDEF
));
2727 stlen
=strlen(de
->d_name
)+1;
2728 h
->st
=(char*) malloc(stlen
*sizeof(char));
2730 strcpy(h
->st
, de
->d_name
);
2740 static char smfbuf
[1000];
2742 char *search_manpath(char *name
)
2747 for (i
=0; manpath
[i
]; i
++) {
2748 strcpy(smfbuf
, manpath
[i
]);
2749 strcat(smfbuf
, name
);
2750 if (stat(smfbuf
, &stbuf
) !=-1) return smfbuf
;
2755 int main(int argc
, char **argv
)
2760 int l
=0,i
;char *buf
;
2766 t
= getenv("PATH_INFO");
2767 if (!t
|| !*t
) /* not : cgi/man2html/mani/name.i */ {
2770 switch (argv
[i
][0]) {
2772 if (argv
[i
][1]=='M') {
2778 manpath
[0]=(char*) malloc(l
+2);
2785 if (isdigit(*s2
)) *s1
=*s2
-'0'; else
2786 *s1
=tolower(*s2
)-'a'+10;
2788 if (isdigit(*s2
)) *s1
=*s1
+*s2
-'0'; else
2789 *s1
=*s1
+tolower(*s2
)-'a'+10;
2794 if (s1
[-1]!='/') { *s1
++='/';*s1
='\0'; }
2798 case '1': case '2': case '3': case '4': case '5': case '6':
2799 case '7': case '8': case '9': case 'n': case 'l':
2801 sectionname
=argv
[i
];
2804 if (!argv
[i
][2] && isalpha(argv
[i
][1]) &&
2805 !isalpha(argv
[i
][0]) && islower(argv
[i
][1])) {
2806 sectionname
=argv
[i
];
2821 t
=s1
=(char*) malloc(l
);
2826 if (isdigit(*s2
)) *s1
=*s2
-'0'; else
2827 *s1
=tolower(*s2
)-'a'+10;
2829 if (isdigit(*s2
)) *s1
=*s1
+*s2
-'0'; else
2830 *s1
=*s1
+tolower(*s2
)-'a'+10;
2837 if (!t
|| !*t
) usage();
2840 while (*h
) i
=i
+(*h
++ == '/');
2844 sprintf(fname
, "man%c/%s.%s", sectionname
[0],t
,sectionname
);
2845 h
=search_manpath(fname
);
2847 printf("Location: " CGIBASE
"%s\n\n", h
);
2850 if (sectionname
[1]) fname
[strlen(fname
)-1]='\0';
2851 i
=search_manpath_section(t
,sectionname
);
2855 if (!i
) i
=search_manpath_all(t
);
2856 if (i
==1 || (i
>1 && mopt
)) {
2857 printf("Location: " CGIBASE
"%sman%c/%s\n\n",
2858 manpath
[foundpages
->nr
/256],
2859 sections
[foundpages
->nr
%256],
2863 printf("Content-type: text/html\n\n"
2864 "<HTML><HEAD>\n<TITLE>Index to %s manpages.</TITLE>\n"
2865 "</HEAD><BODY>\n<H1>Index to %s manpages%s%c</H1>\n", t
, t
,
2866 (notinsection
?" for section ":""),
2867 (notinsection
?sectionname
[0]:' '));
2869 printf("Sorry, no manpages available for %s.\n", t
);
2875 printf("<LI><A HREF=\"" CGIBASE
"%sman%c/%s\">"
2876 "%s</A> (%s)\n", manpath
[strd
->nr
/256],
2877 sections
[strd
->nr
%256], strd
->st
, strd
->st
,
2878 manpath
[strd
->nr
/256]);
2883 printf("</BODY></HTML>\n");
2886 printf("Content-type: text/html\n\n");
2889 printf("<HTML><HEAD><TITLE>Manpage: Error</TITLE>\n"
2890 "</HEAD><BODY>\n<H1>Only manpages are allowed</H1>\n"
2891 "You specified a file which did not contain the keyword\n"
2892 "<B>man</B>. To view the file you wanted, use this\n"
2893 "<A HREF=\"file:%s\">link</A> instead\n"
2894 "</BODY></HTML>\n", t
);
2899 printf("<HTML><HEAD><TITLE>Manpage: Error</TITLE>\n"
2900 "</HEAD><BODY>\n<H1>Warning.</H1>\n"
2901 "You still try to get files which are manpages. Using the\n"
2902 "<B>..</B> construction to get to a different directory will\n"
2903 "<B>not</B> work either. If you try this very often, you\n"
2904 "will end up in a black list.\n"
2905 "</BODY></HTML>\n");
2908 h
=search_manpath(t
);
2915 h
=search_manpath(h
);
2922 } else sectionname
=NULL
;
2924 if (!h
) h
=t
; else h
++;
2925 printf("<HTML><HEAD><TITLE>No manpage for %s.</TITLE>\n"
2926 "</HEAD><BODY>\n<H1>No manpage for %s.</H1>\n"
2927 "Sorry, the manpage for %s does not exist%s%s",
2928 h
,h
,h
, (sectionname
? " in section ":""),
2929 (sectionname
?sectionname
:""));
2930 i
=search_manpath_all(h
);
2933 printf(",nor in any other section.\n");
2935 printf("in any section.\n");
2937 "The links to other manual pages are not always correct.\n"
2938 "Normally you will get a list of possible replacements,\n"
2939 "but in this case the manual page just can't be found.\n");
2942 printf(".\nMaybe you can use %s instead.\n<UL>\n",
2943 (i
>1?"one of the following pages":"this page"));
2946 printf("<LI><A HREF=\"" CGIBASE
"%sman%c/%s\">"
2947 "%s</A> (%s)\n", manpath
[strd
->nr
/256],
2948 sections
[strd
->nr
%256], strd
->st
, strd
->st
,
2949 manpath
[strd
->nr
/256]);
2954 printf("</BODY></HTML>\n");
2965 if (stat(h
, &stbuf
)!=-1) l
=stbuf
.st_size
;
2966 buf
= (char*) malloc((l
+5)*sizeof(char));
2968 if (!f
|| !buf
|| !l
) {
2972 if (!t
) t
=h
; else t
++;
2973 printf("<HTML><HEAD><TITLE>No manpage for %s.</TITLE>\n"
2974 "</HEAD><BODY>\n<H1>No manpage for %s.</H1>\n"
2975 "Sorry, unable to convert the manpage for %s.\n"
2976 "</BODY></HTML>\n", t
,t
,t
);
2979 i
=fread(buf
+1,1,l
,f
);
2983 idxfile
=fopen(INDEXFILE
, "a");
2985 stdf
=&standardchar
[0];
2988 stdf
->next
=&standardchar
[i
];
2992 chardef
=&standardchar
[0];
2993 stdf
=&standardstring
[0];
2996 stdf
->next
=&standardstring
[i
];
3000 strdef
=&standardstring
[0];
3001 intdef
=&standardint
[0];
3003 while (intdef
->nr
) {
3004 intdef
->next
=&standardint
[i
];
3005 intdef
=intdef
->next
;
3008 intdef
=&standardint
[0];
3012 buf
[l
+1]=buf
[l
+2]='\0';
3013 scan_troff(buf
+1,0,NULL
);
3014 while (itemdepth
|| dl_set
[itemdepth
]) {
3015 out_html("</DL>\n");
3016 if (dl_set
[itemdepth
]) dl_set
[itemdepth
]=0;
3019 out_html(change_to_font(0));
3020 out_html(change_to_size(0));
3026 if (output_possible
) {
3027 /* for mosaic users */
3028 printf("<HR>\n<A NAME=\"index\"> </A><H2>Index</H2>\n<DL>\n");
3031 if (subs
) printf("</DL>\n");
3034 printf("</BODY>\n</HTML>\n");
3036 printf("<HTML><HEAD><TITLE>Invalid Manpage</TITLE></HEAD>\n"
3037 "<BODY><H1>Invalid Manpage</H1>\n"
3038 "You tried to retrieve an incorrect manpage.\n"
3039 "The page does not contain a manpage header and will\n"
3040 "not produce any output.\n"
3041 "If the page is a formatted manpage, you might want to use\n"
3042 "a different man2html (or cat2html) converter.\n"
3043 "You can also try to load the\n"
3044 "<A HREF=\"file://localhost%s\">plain file</A>\n",
3047 printf("</BODY>\n</HTML>\n");
3050 if (idxfile
) fclose(idxfile
);