Added lirc.
[irreco.git] / lirc-0.8.4a / doc / man2html.c
blobe1cce3140e1490deeaf15ffe4c5f2faea05bb30a
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 as long
6 ** as this comment is not removed or changed.
7 */
8 /*
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:
34 ** ^^^
35 ** Recognition Item Link
36 ** ----------------------------------------------------------
37 ** name(*) Manpage ../man?/name.*
38 ** ^
39 ** name@hostname Email address mailto:name@hostname
40 ** ^
41 ** method://string URL method://string
42 ** ^^^
43 ** www.host.name WWW server http://www.host.name
44 ** ^^^^
45 ** ftp.host.name FTP server ftp://ftp.host.name
46 ** ^^^^
47 ** <file.h> Include file file:/usr/include/file.h
48 ** ^^^
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.)
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <unistd.h>
88 #include <string.h>
89 #include <sys/stat.h>
90 #include <dirent.h>
91 #include <ctype.h>
92 #include <sys/types.h>
93 #include <time.h>
94 #include <sys/time.h>
96 #ifndef CGIBASE
97 #define CGIBASE "http://wsinwp01.win.tue.nl:1234/cgi-bin/man2html"
98 #endif
100 #ifndef NROFF
101 #define NROFF 1
102 #endif
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"
108 "Time: %s\n";
110 /* timeformat for signature */
111 #define TIMEFORMAT "%T GMT, %B %d, %Y"
113 char *manpath[] = { "/",
114 "/usr/X11/man/",
115 "/usr/man/",
116 "/usr/local/man/",
117 "/usr/exp/man/",
118 "/usr/openwin/man/",
119 "/usr/tex/man/",
120 "/usr/www/man/",
121 "/usr/lang/man/",
122 "/usr/gnu/man/",
123 "/usr/motif/man/",
124 "/usr/titools/man/",
125 "/usr/sunpc/man/",
126 "/usr/ncd/man/",
127 "/usr/newsprint/man/",
128 NULL };
130 char *sections = "123456789nl";
132 void usage(void)
134 printf("Content-type: text/html\n\n"
135 "<HTML><HEAD>\n"
136 "<TITLE>Manual Pages</TITLE>\n"
137 "</HEAD><BODY>\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"
146 "</UL>\n"
147 "<ISINDEX>\n"
148 "<P>\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"
152 "</BODY></HTML>\n");
153 exit(0);
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;
162 struct STRDEF {
163 int nr,slen;
164 char *st;
165 STRDEF *next;
168 typedef struct INTDEF INTDEF;
169 struct INTDEF {
170 int nr;
171 int val;
172 int incr;
173 INTDEF *next;
176 static char NEWLINE[2]="\n";
177 static char idxlabel[6] = "ixAAA";
179 #define INDEXFILE "/tmp/manindex.list"
181 char *fname;
182 FILE *idxfile;
184 STRDEF *chardef, *strdef, *defdef;
185 INTDEF *intdef;
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 */
199 { 0, 0, 0, NULL } };
201 STRDEF standardstring[] = {
202 { V('R',' '), 1, "&#174;", NULL },
203 { V('l','q'), 2, "``", NULL },
204 { V('r','q'), 2, "''", NULL },
205 { 0, 0, NULL, 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, "&#181;", 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, "&#177;", NULL },
261 { V('1','2'), 1, "&#189;", NULL },
262 { V('1','4'), 1, "&#188;", NULL },
263 { V('3','4'), 1, "&#190;", NULL },
264 { V('F','i'), 3, "ffi", NULL },
265 { V('F','l'), 3, "ffl", NULL },
266 { V('a','a'), 1, "&#180;", 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, "&#169;", NULL },
273 { V('c','t'), 1, "&#162;", NULL },
274 { V('d','e'), 1, "&#176;", NULL },
275 { V('d','g'), 1, "+", NULL },
276 { V('d','i'), 1, "&#247;", NULL },
277 { V('e','m'), 1, "-", NULL },
278 { V('e','m'), 3, "---", NULL },
279 { V('e','q'), 1, "=", NULL },
280 { V('e','s'), 1, "&#216;", 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, "&#180;", NULL },
285 { V('g','a'), 1, "`", NULL },
286 { V('h','y'), 1, "-", NULL },
287 { V('l','c'), 2, "|&#175;", 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, "&#215;", NULL },
292 { V('n','o'), 1, "&#172;", NULL },
293 { V('o','r'), 1, "|", NULL },
294 { V('p','l'), 1, "+", NULL },
295 { V('r','c'), 2, "&#175;|", NULL },
296 { V('r','f'), 2, "_|", NULL },
297 { V('r','g'), 1, "&#174;", NULL },
298 { V('r','k'), 1, "<FONT SIZE=+2>}</FONT>", NULL },
299 { V('r','n'), 1, "&#175;", NULL },
300 { V('r','u'), 1, "_", NULL },
301 { V('s','c'), 1, "&#167;", NULL },
302 { V('s','l'), 1, "/", NULL },
303 { V('s','q'), 2, "[]", NULL },
304 { V('u','l'), 1, "_", NULL },
305 { 0, 0, NULL, NULL }
308 /* default: print code */
311 char eqndelimopen=0, eqndelimclose=0;
312 char escapesym='\\', nobreaksym='\'', controlsym='.', fieldsym=0, padsym=0;
314 char *buffer=NULL;
315 int buffpos=0, buffmax=0;
316 int scaninbuff=0;
317 int itemdepth=0;
318 int dl_set[20]= { 0 };
319 int still_dd=0;
320 int tabstops[20] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
321 int maxtstop=12;
322 int curpos=0;
324 extern char *scan_troff(char *c, int san, char **result);
326 static char **argument=NULL;
328 static char charb[3];
330 void print_sig(void)
332 char datbuf[500];
333 struct tm *timetm;
334 time_t clock;
335 datbuf[0]='\0';
336 #ifdef TIMEFORMAT
337 clock=time(NULL);
338 timetm=gmtime(&clock);
339 strftime(datbuf,500,TIMEFORMAT, timetm);
340 #endif
341 printf(signature, datbuf);
344 char *expand_char(int nr)
346 STRDEF *h;
347 h=chardef;
348 if (!nr) return NULL;
349 while (h)
350 if (h->nr==nr) {
351 curpos+=h->slen;
352 return h->st;
353 } else
354 h=h->next;
355 charb[0]=nr/256;
356 charb[1]=nr%256;
357 charb[2]='\0';
358 curpos+=2;
359 return charb;
362 char *expand_string(int nr)
364 STRDEF *h=strdef;
365 if (!nr) return NULL;
366 while (h)
367 if (h->nr==nr) {
368 curpos+=h->slen;
369 return h->st;
370 } else
371 h=h->next;
372 return NULL;
376 char outbuffer[1024];
377 int obp=0;
378 int no_newline_output=0;
379 int newline_for_fun=0;
380 int output_possible=0;
381 int out_length=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
400 int i,j,nr;
401 char *f, *g,*h;
402 char *idtest[6]; /* url, mailto, www, ftp, manpage */
403 out_length+=strlen(c);
404 /* search for (section) */
405 nr=0;
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&gt;");
412 for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
413 while (nr) {
414 j=-1;
415 for (i=0; i<6; i++)
416 if (idtest[i] && (j<0 || idtest[i]<idtest[j])) j=i;
417 switch (j) {
418 case 5: /* <name.h> */
419 f=idtest[5];
420 h=f+2;
421 g=f;
422 while (g>c && g[-1]!=';') g--;
423 if (g!=c) {
424 char t;
425 t=*g;
426 *g='\0';
427 printf("%s",c);
428 *g=t;*h='\0';
429 printf("<A HREF=\"file:/usr/include/%s\">%s</A>&gt;", g,g);
430 c=f+6;
431 } else {
432 f[5]='\0';
433 printf("%s",c);
434 f[5]=';';
435 c=f+5;
437 break;
438 case 4: /* manpage */
439 f=idtest[j];
440 /* check section */
441 g=strchr(f,')');
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 */
447 h=f-1;
448 /* skip html makeup */
449 while (h>c && *h=='>') {
450 while (h!=c && *h!='<') h--;
451 if (h!=c) h--;
453 if (isalnum(*h)) {
454 char t,sec,subsec, *e;
455 e=h+1;
456 sec=f[1];
457 subsec=f[2];
458 if ((subsec=='X' && f[3]!=')')|| subsec==')') subsec='\0';
459 while (h>c && (isalnum(h[-1]) || h[-1]=='_' ||
460 h[-1]=='-' || h[-1]=='.'))
461 h--;
462 t=*h;
463 *h='\0';
464 printf("%s", c);
465 *h=t;
466 t=*e;
467 *e='\0';
468 #if LIRC_RELATIVE_PATH
469 if (subsec)
470 printf("<A HREF=\"../man%c/%s.%c%c\">%s</A>",
471 sec, h, sec, tolower(subsec), h);
472 else
473 printf("<A HREF=\"../man%c/%s.%c\">%s</A>",
474 sec, h, sec, h);
475 #elif LIRC_ABSOLUTE_PATH
476 if (subsec)
477 printf("<A HREF=\"file:///usr/man/man%c/%s.%c%c\">%s</A>",
478 sec, h, sec, tolower(subsec), h);
479 else
480 printf("<A HREF=\"file:///usr/man/man%c/%s.%c\">%s</A>",
481 sec, h, sec, h);
482 #else
483 /* links to man pages make no sense for us */
484 printf("%s",h);
485 #endif
486 *e=t;
487 c=e;
490 *f='\0';
491 printf("%s", c);
492 *f='(';
493 idtest[4]=f-1;
494 c=f;
495 break; /* manpage */
496 case 3: /* ftp */
497 case 2: /* www */
498 g=f=idtest[j];
499 while (*g && (isalnum(*g) || *g=='_' || *g=='-' || *g=='+' ||
500 *g=='.')) g++;
501 if (g[-1]=='.') g--;
502 if (g-f>4) {
503 char t;
504 t=*f; *f='\0';
505 printf("%s",c);
506 *f=t; t=*g;*g='\0';
507 printf("<A HREF=\"%s://%s\">%s</A>", (j==3?"ftp":"http"),
508 f,f);
509 *g=t;
510 c=g;
511 } else {
512 f[3]='\0';
513 printf("%s",c);
514 c=f+3;
515 f[3]='.';
517 break;
518 case 1: /* mailto */
519 g=f=idtest[1];
520 while (g>c && (isalnum(g[-1]) || g[-1]=='_' || g[-1]=='-' ||
521 g[-1]=='+' || g[-1]=='.' || g[-1]=='%')) g--;
522 h=f+1;
523 while (*h && (isalnum(*h) || *h=='_' || *h=='-' || *h=='+' ||
524 *h=='.')) h++;
525 if (*h=='.') h--;
526 if (h-f>4 && f-g>1) {
527 char t;
528 t=*g;
529 *g='\0';
530 printf("%s",c);
531 *g=t;t=*h;*h='\0';
532 printf("<A HREF=\"mailto:%s\">%s</A>",g,g);
533 *h=t;
534 c=h;
535 } else {
536 *f='\0';
537 printf("%s",c);
538 *f='@';
539 idtest[1]=c;
540 c=f;
542 break;
543 case 0: /* url */
544 g=f=idtest[0];
545 while (g>c && isalpha(g[-1]) && islower(g[-1])) g--;
546 h=f+3;
547 while (*h && !isspace(*h) && *h!='<' && *h!='>' && *h!='"' &&
548 *h!='&') h++;
549 if (f-g>2 && f-g<7 && h-f>3) {
550 char t;
551 t=*g;
552 *g='\0';
553 printf("%s", c);
554 *g=t; t=*h; *h='\0';
555 printf("<A HREF=\"%s\">%s</A>", g,g);
556 *h=t;
557 c=h;
558 } else {
559 f[1]='\0';
560 printf("%s", c);
561 f[1]='/';
562 c=f+1;
564 break;
565 default:
566 break;
568 nr=0;
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&gt;");
575 for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
577 printf("%s", c);
580 int current_font=0;
581 int current_size=0;
582 int fillout=1;
584 void out_html(char *c)
586 if (!c) return;
587 if (no_newline_output) {
588 int i=0;
589 no_newline_output=1;
590 while (c[i]) {
591 if (!no_newline_output) c[i-1]=c[i];
592 if (c[i]=='\n') no_newline_output=0;
593 i++;
595 if (!no_newline_output) c[i-1]=0;
597 if (scaninbuff) {
598 while (*c) {
599 if (buffpos>=buffmax) {
600 char *h;
601 h=realloc(buffer, buffmax*2);
602 if (!h) return;
603 buffer=h;
604 buffmax=buffmax*2;
606 buffer[buffpos++]=*c++;
608 } else
609 if (output_possible) {
610 while (*c) {
611 outbuffer[obp++]=*c;
612 if (*c=='\n' || obp>1000) {
613 outbuffer[obp]='\0';
614 add_links(outbuffer);
615 obp=0;
617 c++;
622 #define FO0 ""
623 #define FC0 ""
624 #define FO1 "<I>"
625 #define FC1 "</I>"
626 #define FO2 "<B>"
627 #define FC2 "</B>"
628 #define FO3 "<TT>"
629 #define FC3 "</TT>"
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)
638 int i;
639 switch (nr) {
640 case '0': 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;
651 current_font=nr%4;
652 return switchfont[i];
655 static char sizebuf[200];
657 char *change_to_size(int nr)
659 int i;
660 switch (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;
663 case '\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 "";
667 i=current_font;
668 sizebuf[0]='\0';
669 strcat(sizebuf, change_to_font(0));
670 if (current_size) strcat(sizebuf, "</FONT>");
671 current_size=nr;
672 if (nr) {
673 int l;
674 strcat(sizebuf, "<FONT SIZE=");
675 l=strlen(sizebuf);
676 if (nr>0) sizebuf[l++]='+'; else sizebuf[l++]='-',nr=-nr;
677 sizebuf[l++]=nr+'0';
678 sizebuf[l++]='>';
679 sizebuf[l]='\0';
681 strcat(sizebuf, change_to_font(i));
682 return sizebuf;
685 int asint=0;
686 int intresult=0;
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)
695 char *h=NULL;
696 char b[5];
697 INTDEF *intd;
698 int exoutputp,exskipescape;
699 int i,j;
701 intresult=0;
702 switch (*c) {
703 case 'e': h="\\"; curpos++;break;
704 case '0':
705 case ' ': h="&nbsp;";curpos++; break;
706 case '|': h=""; break;
707 case '"': SKIPEOL; c--; h=""; break;
708 case '$':
709 if (argument) {
710 c++;
711 i=(*c -'1');
712 if (!(h=argument[i])) h="";
714 break;
715 case 'z':
716 c++;
717 if (*c=='\\') { c=scan_escape(c+1); c--;h=""; }
718 else {
719 b[0]=*c;
720 b[1]='\0';
721 h="";
723 break;
724 case 'k': c++; if (*c=='(') c+=2;
725 case '^':
726 case '!':
727 case '%':
728 case 'a':
729 case 'd':
730 case 'r':
731 case 'u':
732 case '\n':
733 case '&': h=""; break;
734 case '(':
735 c++;
736 i= c[0]*256+c[1];
737 c++;
738 h = expand_char(i);
739 break;
740 case '*':
741 c++;
742 if (*c=='(') {
743 c++;
744 i= c[0]*256+c[1];
745 c++;
746 } else
747 i= *c *256+' ';
748 h = expand_string(i);
749 break;
750 case 'f':
751 c++;
752 if (*c=='\\') {
753 c++;
754 c=scan_escape(c);
755 c--;
756 i=intresult;
757 } else if (*c != '(')
758 i=*c;
759 else {
760 c++;
761 i=c[0]*256+c[1];
762 c++;
764 if (!skip_escape) h=change_to_font(i); else h="";
765 break;
766 case 's':
767 c++;
768 j=0;i=0;
769 if (*c=='-') {j= -1; c++;} else if (*c=='+') {j=1; c++;}
770 if (*c=='0') c++; else if (*c=='\\') {
771 c++;
772 c=scan_escape(c);
773 i=intresult; if (!j) j=1;
774 } else
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="";
778 c--;
779 break;
780 case 'n':
781 c++;
782 j=0;
783 switch (*c) {
784 case '+': j=1; c++; break;
785 case '-': j=-1; c++; break;
786 default: break;
788 if (*c=='(') {
789 c++;
790 i=V(c[0],c[1]);
791 c=c+1;
792 } else {
793 i=V(c[0],' ');
795 intd=intdef;
796 while (intd && intd->nr!=i) intd=intd->next;
797 if (intd) {
798 intd->val=intd->val+j*intd->incr;
799 intresult=intd->val;
800 } else {
801 switch (i) {
802 case V('.','s'): intresult=current_size; break;
803 case V('.','f'): intresult=current_font; break;
804 default: intresult=0; break;
807 h="";
808 break;
809 case 'w':
810 c++;
811 i=*c;
812 c++;
813 exoutputp=output_possible;
814 exskipescape=skip_escape;
815 output_possible=0;
816 skip_escape=1;
817 j=0;
818 while (*c!=i) {
819 j++;
820 if (*c==escapesym) c=scan_escape(c+1); else c++;
822 output_possible=exoutputp;
823 skip_escape=exskipescape;
824 intresult=j;
825 break;
826 case 'l': h="<HR>"; curpos=0;
827 case 'b':
828 case 'v':
829 case 'x':
830 case 'o':
831 case 'L':
832 case 'h':
833 c++;
834 i=*c;
835 c++;
836 exoutputp=output_possible;
837 exskipescape=skip_escape;
838 output_possible=0;
839 skip_escape=1;
840 while (*c != i)
841 if (*c==escapesym) c=scan_escape(c+1);
842 else c++;
843 output_possible=exoutputp;
844 skip_escape=exskipescape;
845 break;
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="&lt;";curpos++; break;
852 case '>': h="&gt;";curpos++; break;
853 case '\\': if (single_escape) { c--; break;}
854 default: b[0]=*c; b[1]=0; h=b; curpos++; break;
856 c++;
857 if (!skip_escape) out_html(h);
858 return c;
861 typedef struct TABLEITEM TABLEITEM;
863 struct TABLEITEM {
864 char *contents;
865 int size,align,valign,colspan,rowspan,font,vleft,vright,space,width;
866 TABLEITEM *next;
869 static TABLEITEM emptyfield = {NULL,0,0,0,1,1,0,0,0,0,0,NULL};
870 typedef struct TABLEROW TABLEROW;
872 struct TABLEROW {
873 TABLEITEM *first;
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)
884 TABLEROW *tr1,*tr2;
885 TABLEITEM *ti1,*ti2;
887 tr1=table;
888 while (tr1->prev) tr1=tr1->prev;
889 while (tr1) {
890 ti1=tr1->first;
891 while (ti1) {
892 ti2=ti1->next;
893 if (ti1->contents) free(ti1->contents);
894 free(ti1);
895 ti1=ti2;
897 tr2=tr1;
898 tr1=tr1->next;
899 free(tr2);
903 char *scan_expression(char *c, int *result);
905 static char *scan_format(char *c, TABLEROW **result, int *maxcol)
907 TABLEROW *layout, *currow;
908 TABLEITEM *curfield;
909 int i,j;
910 if (*result) {
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!='.') {
918 switch (*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':
922 case '^': case '_':
923 if (curfield->align) {
924 curfield->next=(TABLEITEM*)malloc(sizeof(TABLEITEM));
925 curfield=curfield->next;
926 *curfield=emptyfield;
928 curfield->align=toupper(*c);
929 c++;
930 break;
931 case 'i': case 'I': case 'B': case 'b':
932 curfield->font = toupper(*c);
933 c++;
934 break;
935 case 'f': case 'F':
936 c++;
937 curfield->font = toupper(*c);
938 c++;
939 if (!isspace(*c)) c++;
940 break;
941 case 't': case 'T': curfield->valign='t'; c++; break;
942 case 'p': case 'P':
943 c++;
944 i=j=0;
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;
949 break;
950 case 'v': case 'V':
951 case 'w': case 'W':
952 c=scan_expression(c+2,&curfield->width);
953 break;
954 case '|':
955 if (curfield->align) curfield->vleft++;
956 else curfield->vright++;
957 c++;
958 break;
959 case 'e': case 'E':
960 c++;
961 break;
962 case '0': case '1': case '2': case '3': case '4':
963 case '5': case '6': case '7': case '8': case '9':
964 i=0;
965 while (isdigit(*c)) i=i*10+(*c++)-'0';
966 curfield->space=i;
967 break;
968 case ',': case '\n':
969 currow->next=(TABLEROW*)malloc(sizeof(TABLEROW));
970 currow->next->prev=currow;
971 currow=currow->next;
972 currow->next=NULL;
973 curfield=currow->first=(TABLEITEM*)malloc(sizeof(TABLEITEM));
974 *curfield=emptyfield;
975 c++;
976 break;
977 default:
978 c++;
979 break;
982 if (*c=='.') while (*c++!='\n');
983 *maxcol=0;
984 currow=layout;
985 while (currow) {
986 curfield=layout->first;
987 i=0;
988 while (curfield) {
989 i++;
990 curfield=curfield->next;
992 if (i>*maxcol) *maxcol=i;
993 currow=currow->next;
995 *result=layout;
996 return c;
999 TABLEROW *next_row(TABLEROW *tr)
1001 if (tr->next) {
1002 tr=tr->next;
1003 if (!tr->next) next_row(tr);
1004 return tr;
1005 } else {
1006 TABLEITEM *ti, *ti2;
1007 tr->next=(TABLEROW*)malloc(sizeof(TABLEROW));
1008 tr->next->prev=tr;
1009 ti=tr->first;
1010 tr=tr->next;
1011 tr->next=NULL;
1012 if (ti) tr->first=ti2=(TABLEITEM*) malloc(sizeof(TABLEITEM));
1013 else tr->first=ti2=NULL;
1014 while (ti!=ti2) {
1015 *ti2=*ti;
1016 ti2->contents=NULL;
1017 if ((ti=ti->next)) {
1018 ti2->next=(TABLEITEM*) malloc(sizeof(TABLEITEM));
1020 ti2=ti2->next;
1022 return tr;
1026 char itemreset[20]="\\fR\\s0";
1028 char *scan_table(char *c)
1030 char *h, *g;
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;
1034 char itemsep='\t';
1035 TABLEROW *layout=NULL, *currow;
1036 TABLEITEM *curfield;
1037 while (*c++!='\n');
1038 h=c;
1039 if (*h=='.') return c-1;
1040 oldfont=current_font;
1041 oldsize=current_size;
1042 oldfillout=fillout;
1043 out_html(change_to_font(0));
1044 out_html(change_to_size(0));
1045 if (!fillout) {
1046 fillout=1;
1047 out_html("</PRE>");
1049 while (*h && *h!='\n') h++;
1050 if (h[-1]==';') {
1051 /* scan table options */
1052 while (c<h) {
1053 while (isspace(*c)) c++;
1054 for (i=0; tableopt[i] && strncmp(tableopt[i],c,tableoptl[i]);i++);
1055 c=c+tableoptl[i];
1056 switch (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';
1065 break;
1066 case 7: while (*c!=')') c++;
1067 default: break;
1069 c++;
1071 c=h+1;
1073 /* scan layout */
1074 c=scan_format(c,&layout, &maxcol);
1075 currow=layout;
1076 next_row(currow);
1077 curfield=layout->first;
1078 i=0;
1079 while (!finished) {
1080 /* search item */
1081 h=c;
1082 if ((*c=='_' || *c=='=') && (c[1]==itemsep || c[1]=='\n')) {
1083 if (c[-1]=='\n' && c[1]=='\n') {
1084 if (currow->prev) {
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;
1089 } else {
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;
1097 curfield->align=*c;
1098 curfield->colspan=maxcol;
1099 curfield=currow->first;
1100 c=c+2;
1101 } else {
1102 if (curfield) {
1103 curfield->align=*c;
1104 do {
1105 curfield=curfield->next;
1106 } while (curfield && curfield->align=='S');
1108 if (c[1]=='\n') {
1109 currow=next_row(currow);
1110 curfield=currow->first;
1112 c=c+2;
1114 } else if (*c=='T' && c[1]=='{') {
1115 h=c+2;
1116 c=strstr(h,"\nT}");
1117 c++;
1118 *c='\0';
1119 g=NULL;
1120 scan_troff(h,0,&g);
1121 scan_troff(itemreset, 0,&g);
1122 *c='T';
1123 c+=3;
1124 if (curfield) {
1125 curfield->contents=g;
1126 do {
1127 curfield=curfield->next;
1128 } while (curfield && curfield->align=='S');
1129 } else
1130 if (g) free(g);
1131 if (c[-1]=='\n') {
1132 currow=next_row(currow);
1133 curfield=currow->first;
1135 } else if (*c=='.' && c[1]=='T' && c[2]=='&' && c[-1]=='\n') {
1136 TABLEROW *hr;
1137 while (*c++!='\n');
1138 hr=currow;
1139 currow=currow->prev;
1140 hr->prev=NULL;
1141 c=scan_format(c,&hr, &i);
1142 hr->prev=currow;
1143 currow->next=hr;
1144 currow=hr;
1145 next_row(currow);
1146 curfield=currow->first;
1147 } else if (*c=='.' && c[1]=='T' && c[2]=='E' && c[-1]=='\n') {
1148 finished=1;
1149 while (*c++!='\n');
1150 if (currow->prev)
1151 currow->prev->next=NULL;
1152 currow->prev=NULL;
1153 clear_table(currow);
1154 } else if (*c=='.' && c[-1]=='\n' && !isdigit(c[1])) {
1155 /* skip troff request inside table (usually only .sp ) */
1156 while (*c++!='\n');
1157 } else {
1158 h=c;
1159 while (*c && (*c!=itemsep || c[-1]=='\\') &&
1160 (*c!='\n' || c[-1]=='\\')) c++;
1161 i=0;
1162 if (*c==itemsep) {i=1; *c='\n'; }
1163 if (h[0]=='\\' && h[2]=='\n' &&
1164 (h[1]=='_' || h[1]=='^')) {
1165 if (curfield) {
1166 curfield->align=h[1];
1167 do {
1168 curfield=curfield->next;
1169 } while (curfield && curfield->align=='S');
1171 h=h+3;
1172 } else {
1173 g=NULL;
1174 h=scan_troff(h,1,&g);
1175 scan_troff(itemreset,0,&g);
1176 if (curfield) {
1177 curfield->contents=g;
1178 do {
1179 curfield=curfield->next;
1180 } while (curfield && curfield->align=='S');
1181 } else if (g) free(g);
1183 if (i) *c=itemsep;
1184 c=h;
1185 if (c[-1]=='\n') {
1186 currow=next_row(currow);
1187 curfield=currow->first;
1191 /* calculate colspan and rowspan */
1192 currow=layout;
1193 while (currow->next) currow=currow->next;
1194 while (currow) {
1195 TABLEITEM *ti, *ti1=NULL, *ti2=NULL;
1196 ti=currow->first;
1197 if (currow->prev) ti1=currow->prev->first;
1198 while (ti) {
1199 switch (ti->align) {
1200 case 'S':
1201 if (ti2) {
1202 ti2->colspan++;
1203 if (ti2->rowspan<ti->rowspan) ti2->rowspan=ti->rowspan;
1205 break;
1206 case '^':
1207 if (ti1) ti1->rowspan++;
1208 default:
1209 if (!ti2) ti2=ti;
1210 else {
1211 do {
1212 ti2=ti2->next;
1213 } while (ti2 && curfield->align=='S');
1215 break;
1217 ti=ti->next;
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>");
1225 out_html("<TABLE");
1226 if (box || border) {
1227 out_html(" BORDER");
1228 if (!border) out_html("><TR><TD><TABLE");
1229 if (expand) out_html(" WIDTH=100%");
1231 out_html(">\n");
1232 currow=layout;
1233 while (currow) {
1234 j=0;
1235 out_html("<TR VALIGN=top>");
1236 curfield=currow->first;
1237 while (curfield) {
1238 if (curfield->align!='S' && curfield->align!='^') {
1239 out_html("<TD");
1240 switch (curfield->align) {
1241 case 'N':
1242 curfield->space+=4;
1243 case 'R':
1244 out_html(" ALIGN=right");
1245 break;
1246 case 'C':
1247 out_html(" ALIGN=center");
1248 default:
1249 break;
1251 if (!curfield->valign && curfield->rowspan>1)
1252 out_html(" VALIGN=center");
1253 if (curfield->colspan>1) {
1254 char buf[5];
1255 out_html(" COLSPAN=");
1256 sprintf(buf, "%i", curfield->colspan);
1257 out_html(buf);
1259 if (curfield->rowspan>1) {
1260 char buf[5];
1261 out_html(" ROWSPAN=");
1262 sprintf(buf, "%i", curfield->rowspan);
1263 out_html(buf);
1265 j=j+curfield->colspan;
1266 out_html(">");
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;
1272 default:
1273 if (curfield->contents) out_html(curfield->contents);
1274 break;
1276 if (curfield->space)
1277 for (i=0; i<curfield->space;i++) out_html("&nbsp;");
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!='_')
1281 out_html("<BR>");
1282 out_html("</TD>");
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>");
1295 fillout=oldfillout;
1296 out_html(change_to_size(oldsize));
1297 out_html(change_to_font(oldfont));
1298 return c;
1301 char *scan_expression(char *c, int *result)
1303 int value=0,value2,sign=1,opex=0;
1304 char oper='c';
1306 if (*c=='!') {
1307 c=scan_expression(c+1, &value);
1308 value= (!value);
1309 } else if (*c=='n') {
1310 c++;
1311 value=NROFF;
1312 } else if (*c=='t') {
1313 c++;
1314 value=1-NROFF;
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;
1320 char *tcmp=NULL;
1321 char sep;
1322 sep=*c;
1323 if (sep=='\\') {
1324 tcmp=c;
1325 c=c+3;
1327 c++;
1328 h=c;
1329 while (*c!= sep && (!tcmp || strncmp(c,tcmp,4))) c++;
1330 *c='\n';
1331 scan_troff(h, 1, &st1);
1332 *c=sep;
1333 if (tcmp) c=c+3;
1334 c++;
1335 h=c;
1336 while (*c!=sep && (!tcmp || strncmp(c,tcmp,4))) c++;
1337 *c='\n';
1338 scan_troff(h,1,&st2);
1339 *c=sep;
1340 if (!st1 && !st2) value=1;
1341 else if (!st1 || !st2) value=0;
1342 else value=(!strcmp(st1, st2));
1343 if (st1) free(st1);
1344 if (st2) free(st2);
1345 if (tcmp) c=c+3;
1346 c++;
1347 } else {
1348 while (*c && !isspace(*c) && *c!=')') {
1349 opex=0;
1350 switch (*c) {
1351 case '(':
1352 c=scan_expression(c+1, &value2);
1353 value2=sign*value2;
1354 opex=1;
1355 break;
1356 case '.':
1357 case '0': case '1':
1358 case '2': case '3':
1359 case '4': case '5':
1360 case '6': case '7':
1361 case '8': case '9': {
1362 int num=0,denum=1;
1363 value2=0;
1364 while (isdigit(*c)) value2=value2*10+((*c++)-'0');
1365 if (*c=='.') {
1366 c++;
1367 while (isdigit(*c)) {
1368 num=num*10+((*c++)-'0');
1369 denum=denum*10;
1372 if (isalpha(*c)) {
1373 /* scale indicator */
1374 switch (*c) {
1375 case 'i': /* inch -> 10pt */
1376 value2=value2*10+(num*10+denum/2)/denum;
1377 num=0;
1378 break;
1379 default:
1380 break;
1382 c++;
1384 value2=value2+(num+denum/2)/denum;
1385 value2=sign*value2;
1386 opex=1;
1387 break;
1389 case '\\':
1390 c=scan_escape(c+1);
1391 value2=intresult*sign;
1392 if (isalpha(*c)) c++; /* scale indicator */
1393 opex=1;
1394 break;
1395 case '-':
1396 if (oper) { sign=-1; c++; break; }
1397 case '>':
1398 case '<':
1399 case '+':
1400 case '/':
1401 case '*':
1402 case '%':
1403 case '&':
1404 case '=':
1405 case ':':
1406 if (c[1]=='=') oper=(*c++) +16; else oper=*c;
1407 c++;
1408 break;
1409 default: c++; break;
1411 if (opex) {
1412 sign=1;
1413 switch (oper) {
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);
1429 oper=0;
1432 if (*c==')') c++;
1434 *result=value;
1435 return c;
1438 void trans_char(char *c, char s, char t)
1440 char *sl=c;
1441 int slash=0;
1442 while (*sl!='\n' || slash) {
1443 if (!slash) {
1444 if (*sl==escapesym)
1445 slash=1;
1446 else if (*sl==s)
1447 *sl=t;
1448 } else slash=0;
1449 sl++;
1453 char *fill_words(char *c, char *words[], int *n)
1455 char *sl=c;
1456 int slash=0;
1457 int skipspace=0;
1458 *n=0;
1459 words[*n]=sl;
1460 while (*sl && (*sl!='\n' || slash)) {
1461 if (!slash) {
1462 if (*sl=='"') {
1463 *sl='\a';
1464 skipspace=!skipspace;
1465 } else if (*sl==escapesym)
1466 slash=1;
1467 else if ((*sl==' ' || *sl=='\t') && !skipspace) {
1468 *sl='\n';
1469 if (words[*n]!=sl) (*n)++;
1470 words[*n]=sl+1;
1472 } else {
1473 if (*sl=='"') {
1474 sl--;
1475 *sl='\n';
1476 if (words[*n]!=sl) (*n)++;
1477 sl++;
1478 while (*sl && *sl !='\n') sl++;
1479 words[*n]=sl;
1480 sl--;
1482 slash=0;
1484 sl++;
1486 if (sl!=words[*n]) (*n)++;
1487 return sl;
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 &amp; 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",
1533 NULL, NULL };
1535 char *lookup_abbrev(char *c)
1537 int i=0;
1539 if (!c) return "";
1540 while (abbrev_list[i] && strcmp(c,abbrev_list[i])) i=i+2;
1541 if (abbrev_list[i]) return abbrev_list[i+1];
1542 else return c;
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",
1569 "4P", "Protocols",
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",
1582 /* for Solaris:
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",
1641 "9", "DDI and DKI",
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",
1651 NULL, NULL
1654 char *section_name(char *c)
1656 int i=0;
1658 if (!c) return "";
1659 while (section_list[i] && strcmp(c,section_list[i])) i=i+2;
1660 if (section_list[i+1]) return section_list[i+1];
1661 else return c;
1664 char manidx[20000];
1665 int subs=0;
1666 int mip=0;
1667 char label[5]="lbAA";
1669 void add_to_index(int level, char *item)
1671 char *c=NULL;
1672 label[3]++;
1673 if (label[3]>'Z') {
1674 label[3]='A';
1675 label[2]++;
1677 if (level != subs) {
1678 if (subs) {
1679 strcpy(manidx+mip, "</DL>\n");
1680 mip+=6;
1681 } else {
1682 strcpy(manidx+mip, "<DL>\n");
1683 mip+=5;
1686 subs=level;
1687 scan_troff(item, 1, &c);
1688 sprintf(manidx+mip, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label, c);
1689 if (c) free(c);
1690 while (manidx[mip]) mip++;
1693 char *skip_till_newline(char *c)
1695 int lvl=0;
1697 while ((*c && *c!='\n') || (lvl>0)) {
1698 if (*c=='\\') {
1699 c++;
1700 if (*c=='}') lvl--; else if (*c=='{') lvl++;
1702 c++;
1704 c++;
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;
1709 return c;
1712 int ifelseval=0;
1714 char *scan_request(char *c)
1716 int i,j,mode=0;
1717 char *h;
1718 char *wordlist[20];
1719 int words;
1720 char *sl;
1721 STRDEF *owndef;
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);
1730 else
1731 c = scan_escape(c+1);
1732 } else {
1733 i=V(c[0],c[1]);
1734 switch (i) {
1735 case V('a','b'):
1736 h=c+j;
1737 while (*h && *h !='\n') h++;
1738 *h='\0';
1739 if (scaninbuff && buffpos) {
1740 buffer[buffpos]='\0';
1741 printf("%s\n", buffer);
1743 fprintf(stderr, "%s\n", c+2);
1744 exit(0);
1745 break;
1746 case V('d','i'):
1748 STRDEF *de;
1749 c=c+j;
1750 i=V(c[0],c[1]);
1751 if (*c=='\n') { c++;break; }
1752 while (*c && *c!='\n') c++;
1753 c++;
1754 h=c;
1755 while (*c && strncmp(c,".di",3)) while (*c && *c++!='\n');
1756 *c='\0';
1757 de=strdef;
1758 while (de && de->nr !=i) de=de->next;
1759 if (!de) {
1760 de=(STRDEF*) malloc(sizeof(STRDEF));
1761 de->nr=i;
1762 de->slen=0;
1763 de->next=strdef;
1764 de->st=NULL;
1765 strdef=de;
1766 } else {
1767 if (de->st) free(de->st);
1768 de->slen=0;
1769 de->st=NULL;
1771 scan_troff(h,0,&de->st);
1772 *c='.';
1773 while (*c && *c++!='\n');
1774 break;
1776 case V('d','s'):
1777 mode=1;
1778 case V('a','s'):
1780 STRDEF *de;
1781 int oldcurpos=curpos;
1782 c=c+j;
1783 i=V(c[0],c[1]);
1784 j=0;
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++;
1789 if (*c=='"') c++;
1790 de=strdef;
1791 while (de && de->nr != i) de=de->next;
1792 single_escape=1;
1793 curpos=0;
1794 if (!de) {
1795 char *h;
1796 de=(STRDEF*) malloc(sizeof(STRDEF));
1797 de->nr=i;
1798 de->slen=0;
1799 de->next=strdef;
1800 de->st=NULL;
1801 strdef=de;
1802 h=NULL;
1803 c=scan_troff(c, 1, &h);
1804 de->st=h;
1805 de->slen=curpos;
1806 } else {
1807 if (mode) {
1808 char *h=NULL;
1809 c=scan_troff(c, 1, &h);
1810 free(de->st);
1811 de->slen=0;
1812 de->st=h;
1813 } else
1814 c=scan_troff(c,1,&de->st);
1815 de->slen+=curpos;
1817 single_escape=0;
1818 curpos=oldcurpos;
1820 break;
1821 case V('b','r'):
1822 if (still_dd) out_html("<DD>");
1823 else out_html("<BR>\n");
1824 curpos=0;
1825 c=c+j;
1826 if (c[0]==escapesym) { c=scan_escape(c+1); }
1827 c=skip_till_newline(c);break;
1828 case V('c','2'):
1829 c=c+j;
1830 if (*c!='\n') { nobreaksym=*c; }
1831 else nobreaksym='\'';
1832 c=skip_till_newline(c);
1833 break;
1834 case V('c','c'):
1835 c=c+j;
1836 if (*c!='\n') { controlsym=*c; }
1837 else controlsym='.';
1838 c=skip_till_newline(c);
1839 break;
1840 case V('c','e'):
1841 c=c+j;
1842 if (*c=='\n') { i=1; }
1843 else {
1844 i=0;
1845 while ('0'<=*c && *c<='9') {
1846 i=i*10+*c-'0';
1847 c++;
1850 c=skip_till_newline(c);
1851 /* center next i lines */
1852 if (i>0) {
1853 out_html("<CENTER>\n");
1854 while (i && *c) {
1855 char *line=NULL;
1856 c=scan_troff(c,1, &line);
1857 if (line && strncmp(line, "<BR>", 4)) {
1858 out_html(line);
1859 out_html("<BR>\n");
1860 i--;
1863 out_html("</CENTER>\n");
1864 curpos=0;
1866 break;
1867 case V('e','c'):
1868 c=c+j;
1869 if (*c!='\n') { escapesym=*c; }
1870 else escapesym='\\';
1871 break;
1872 c=skip_till_newline(c);
1873 case V('e','o'):
1874 escapesym='\0';
1875 c=skip_till_newline(c);
1876 break;
1877 case V('e','x'):
1878 exit(0);
1879 break;
1880 case V('f','c'):
1881 c=c+j;
1882 if (*c=='\n') {
1883 fieldsym=padsym='\0';
1884 } else {
1885 fieldsym=c[0];
1886 padsym=c[1];
1888 c=skip_till_newline(c);
1889 break;
1890 case V('f','i'):
1891 if (!fillout) {
1892 out_html(change_to_font(0));
1893 out_html(change_to_size('0'));
1894 out_html("</PRE>\n");
1896 curpos=0;
1897 fillout=1;
1898 c=skip_till_newline(c);
1899 break;
1900 case V('f','t'):
1901 c=c+j;
1902 if (*c=='\n') {
1903 out_html(change_to_font(0));
1904 } else {
1905 if (*c==escapesym) {
1906 int fn;
1907 c=scan_expression(c, &fn);
1908 c--;
1909 out_html(change_to_font(fn));
1910 } else {
1911 out_html(change_to_font(*c));
1912 c++;
1915 c=skip_till_newline(c);
1916 break;
1917 case V('e','l'):
1918 /* .el anything : else part of if else */
1919 if (ifelseval) {
1920 c=c+j;
1921 c[-1]='\n';
1922 c=scan_troff(c,1,NULL);
1923 } else
1924 c=skip_till_newline(c+j);
1925 break;
1926 case V('i','e'):
1927 /* .ie c anything : then part of if else */
1928 case V('i','f'):
1929 /* .if c anything
1930 * .if !c anything
1931 * .if N anything
1932 * .if !N anything
1933 * .if 'string1'string2' anything
1934 * .if !'string1'string2' anything
1936 c=c+j;
1937 c=scan_expression(c, &i);
1938 ifelseval=!i;
1939 if (i) {
1940 *c='\n';
1941 c++;
1942 c=scan_troff(c,1,NULL);
1943 } else
1944 c=skip_till_newline(c);
1945 break;
1946 case V('i','g'):
1948 char *endwith="..\n";
1949 i=3;
1950 c=c+j;
1951 if (*c!='\n') {
1952 endwith=c-1;i=1;
1953 c[-1]='.';
1954 while (*c!='\n') c++,i++;
1956 c++;
1957 while (*c && strncmp(c,endwith,i)) while (*c++!='\n');
1958 while (*c++!='\n');
1959 break;
1961 case V('n','f'):
1962 if (fillout) {
1963 out_html(change_to_font(0));
1964 out_html(change_to_size('0'));
1965 out_html("<PRE>\n");
1967 curpos=0;
1968 fillout=0;
1969 c=skip_till_newline(c);
1970 break;
1971 case V('p','s'):
1972 c=c+j;
1973 if (*c=='\n') {
1974 out_html(change_to_size('0'));
1975 } else {
1976 j=0;i=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);
1983 break;
1984 case V('s','p'):
1985 c=c+j;
1986 if (fillout) out_html("<P>"); else {
1987 out_html(NEWLINE);
1988 NEWLINE[0]='\n';
1990 curpos=0;
1991 c=skip_till_newline(c);
1992 break;
1993 case V('s','o'):
1995 FILE *f;
1996 struct stat stbuf;
1997 int l=0;char *buf;
1998 char *name=NULL;
1999 curpos=0;
2000 c=c+j;
2001 if (*c=='/') {
2002 h=c;
2003 } else {
2004 h=c-3;
2005 h[0]='.';
2006 h[1]='.';
2007 h[2]='/';
2009 while (*c!='\n') c++;
2010 *c='\0';
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));
2015 #if NOCGI
2016 if (!out_length) {
2017 char *t,*s;
2018 t=strrchr(fname, '/');
2019 if (!t) t=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"
2023 "</HEAD><BODY>\n"
2024 "See the manpage for <A HREF=\"%s.html\">%s</A>.\n"
2025 "</BODY></HTML>\n",
2026 s, h, h);
2027 } else
2028 #endif
2030 /* this works alright, except for section 3 */
2031 f=fopen(h,"r");
2032 if (!f || !buf || !l)
2033 fprintf(stderr, "Unable to open or read file %s.\n",
2034 h);
2035 else {
2036 i=fread(buf+1,1,l,f);
2037 fclose(f);
2038 buf[0]=buf[l]='\n';
2039 buf[l+1]=buf[l+2]='\0';
2040 scan_troff(buf+1,0,NULL);
2042 if (buf) free(buf);
2044 *c++='\n';
2045 break;
2047 case V('t','a'):
2048 c=c+j;
2049 j=0;
2050 while (*c!='\n') {
2051 sl=scan_expression(c, &tabstops[j]);
2052 if (*c=='-' || *c=='+') tabstops[j]+=tabstops[j-1];
2053 c=sl;
2054 while (*c==' ' || *c=='\t') c++;
2055 j++;
2057 maxtstop=j;
2058 curpos=0;
2059 break;
2060 case V('t','i'):
2061 /*while (itemdepth || dl_set[itemdepth]) {
2062 out_html("</DL>\n");
2063 if (dl_set[itemdepth]) dl_set[itemdepth]=0;
2064 else itemdepth--;
2066 out_html("<BR>\n");
2067 c=c+j;
2068 c=scan_expression(c, &j);
2069 for (i=0; i<j; i++) out_html("&nbsp;");
2070 curpos=j;
2071 c=skip_till_newline(c);
2072 break;
2073 case V('t','m'):
2074 c=c+j;
2075 h=c;
2076 while (*c!='\n') c++;
2077 *c='\0';
2078 fprintf(stderr,"%s\n", h);
2079 *c='\n';
2080 break;
2081 case V('B',' '):
2082 case V('B','\n'):
2083 case V('I',' '):
2084 case V('I','\n'):
2085 /* parse one line in a certain font */
2086 out_html(change_to_font(*c));
2087 trans_char(c,'"','\a');
2088 c=c+j;
2089 if (*c=='\n') c++;
2090 c=scan_troff(c, 1, NULL);
2091 out_html(change_to_font('R'));
2092 out_html(NEWLINE);
2093 if (fillout) curpos++; else curpos=0;
2094 break;
2095 case V('O','P'): /* groff manpages use this construction */
2096 /* .OP a b : [ <B>a</B> <I>b</I> ] */
2097 mode=1;
2098 c[0]='B'; c[1]='I';
2099 out_html(change_to_font('R'));
2100 out_html("[");
2101 curpos++;
2102 case V('B','R'):
2103 case V('B','I'):
2104 case V('I','B'):
2105 case V('I','R'):
2106 case V('R','B'):
2107 case V('R','I'):
2109 char font[2] = { c[0], c[1] };
2110 c=c+j;
2111 if (*c=='\n') c++;
2112 sl=fill_words(c, wordlist, &words);
2113 c=sl+1;
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++;
2127 break;
2128 case V('D','T'):
2129 for (j=0;j<20; j++) tabstops[j]=(j+1)*8;
2130 maxtstop=20;
2131 c=skip_till_newline(c); break;
2132 case V('I','P'):
2133 sl=fill_words(c+j, wordlist, &words);
2134 c=sl+1;
2135 if (!dl_set[itemdepth]) {
2136 out_html("<DL COMPACT>\n");
2137 dl_set[itemdepth]=1;
2139 out_html("<DT>");
2140 if (words) {
2141 scan_troff(wordlist[0], 1,NULL);
2143 out_html("<DD>");
2144 curpos=0;
2145 break;
2146 case V('T','P'):
2147 if (!dl_set[itemdepth]) {
2148 out_html("<DL COMPACT>\n");
2149 dl_set[itemdepth]=1;
2151 out_html("<DT>");
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);
2156 out_html("<DD>");
2158 curpos=0;
2159 break;
2160 case V('I','X'):
2161 /* general index */
2162 sl = fill_words(c+j, wordlist, &words);
2163 c=sl+1;
2164 j=4;
2165 while (idxlabel[j]=='Z') idxlabel[j--]='A';
2166 idxlabel[j]++;
2167 #ifdef MAKEINDEX
2168 fprintf(idxfile, "%s@%s@", fname, idxlabel);
2169 for (j=0; j<words; j++) {
2170 h=NULL;
2171 scan_troff(wordlist[j], 1, &h);
2172 fprintf(idxfile, "_\b@%s", h);
2173 free(h);
2175 fprintf(idxfile,"\n");
2176 #endif
2177 out_html("<A NAME=\"");
2178 out_html(idxlabel);
2179 /* this will not work in mosaic (due to a bug).
2180 ** Adding '&nbsp;' between '>' and '<' solves it, but creates
2181 ** some space. A normal space does not work.
2183 out_html("\"></A>");
2184 break;
2185 case V('L','P'):
2186 case V('P','P'):
2187 if (dl_set[itemdepth]) {
2188 out_html("</DL>\n");
2189 dl_set[itemdepth]=0;
2191 if (fillout) out_html("<P>\n"); else {
2192 out_html(NEWLINE);
2193 NEWLINE[0]='\n';
2195 curpos=0;
2196 c=skip_till_newline(c);
2197 break;
2198 case V('H','P'):
2199 if (!dl_set[itemdepth]) {
2200 out_html("<DL COMPACT>");
2201 dl_set[itemdepth]=1;
2203 out_html("<DT>\n");
2204 still_dd=1;
2205 c=skip_till_newline(c);
2206 curpos=0;
2207 break;
2208 case V('P','D'): c=skip_till_newline(c); break;
2209 case V('R','S'):
2210 sl=fill_words(c+j, wordlist, &words);
2211 j=1;
2212 if (words>0) scan_expression(wordlist[0], &j);
2213 if (j>=0) {
2214 itemdepth++;
2215 dl_set[itemdepth]=0;
2216 out_html("<DL COMPACT><DT><DD>");
2217 c=skip_till_newline(c);
2218 curpos=0;
2219 break;
2221 case V('R','E'):
2222 if (itemdepth) {
2223 if (dl_set[itemdepth]) out_html("</DL>");
2224 out_html("</DL>\n");
2225 itemdepth--;
2227 c=skip_till_newline(c);
2228 curpos=0;
2229 break;
2230 case V('S','B'):
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'));
2236 break;
2237 case V('S','M'):
2238 c=c+j;
2239 if (*c=='\n') c++;
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'));
2244 break;
2245 case V('S','S'):
2246 mode=1;
2247 case V('S','H'):
2248 c=c+j;
2249 if (*c=='\n') c++;
2250 while (itemdepth || dl_set[itemdepth]) {
2251 out_html("</DL>\n");
2252 if (dl_set[itemdepth]) dl_set[itemdepth]=0;
2253 else itemdepth--;
2255 out_html(change_to_font(0));
2256 out_html(change_to_size(0));
2257 if (!fillout) {
2258 fillout=1;
2259 out_html("</PRE>");
2261 trans_char(c,'"', '\a');
2262 add_to_index(mode, c);
2263 out_html("<A NAME=\"");
2264 out_html(label);
2265 /* &nbsp; for mosaic users */
2266 if (mode) out_html("\">&nbsp;</A>\n<H3>");
2267 else out_html("\">&nbsp;</A>\n<H2>");
2268 c=scan_troff(c,1,NULL);
2269 if (mode) out_html("</H3>\n");
2270 else out_html("</H2>\n");
2271 curpos=0;
2272 break;
2273 case V('T','S'):
2274 c=scan_table(c);
2275 break;
2276 case V('T','H'):
2277 if (!output_possible) {
2278 sl = fill_words(c+j, wordlist, &words);
2279 if (words>1) {
2280 for (i=1; i<words; i++) wordlist[i][-1]='\0';
2281 *sl='\0';
2282 output_possible=1;
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]);
2289 else
2290 out_html(section_name(wordlist[1]));
2291 out_html(" (");
2292 out_html(wordlist[1]);
2293 if (words>2) {
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");
2298 *sl='\n';
2299 out_html("<HR>\n");
2301 c=sl+1;
2302 } else c=skip_till_newline(c);
2303 curpos=0;
2304 break;
2305 case V('T','X'):
2306 sl=fill_words(c+j, wordlist, &words);
2307 *sl='\0';
2308 out_html(change_to_font('I'));
2309 if (words>1) wordlist[1][-1]='\0';
2310 c=lookup_abbrev(wordlist[0]);
2311 curpos+=strlen(c);
2312 out_html(c);
2313 out_html(change_to_font('R'));
2314 if (words>1)
2315 out_html(wordlist[1]);
2316 *sl='\n';
2317 c=sl+1;
2318 break;
2319 case V('r','m'):
2320 /* .rm xx : Remove request, macro or string */
2321 case V('r','n'):
2322 /* .rn xx yy : Rename request, macro or string xx to yy */
2324 STRDEF *de;
2325 c=c+j;
2326 i=V(c[0],c[1]);
2327 c=c+2;
2328 while (isspace(*c) && *c!='\n') c++;
2329 j=V(c[0],c[1]);
2330 while (*c && *c!='\n') c++;
2331 c++;
2332 de=strdef;
2333 while (de && de->nr!=j) de=de->next;
2334 if (de) {
2335 if (de->st) free(de->st);
2336 de->nr=0;
2338 de=strdef;
2339 while (de && de->nr!=i) de=de->next;
2340 if (de) de->nr=j;
2341 break;
2343 case V('n','x'):
2344 /* .nx filename : next file. */
2345 case V('i','n'):
2346 /* .in +-N : Indent */
2347 c=skip_till_newline(c);
2348 break;
2349 case V('n','r'):
2350 /* .nr R +-N M: define and set number register R by +-N;
2351 ** auto-increment by M
2354 INTDEF *intd;
2355 c=c+j;
2356 i=V(c[0],c[1]);
2357 c=c+2;
2358 intd=intdef;
2359 while (intd && intd->nr!=i) intd=intd->next;
2360 if (!intd) {
2361 intd = (INTDEF*) malloc(sizeof(INTDEF));
2362 intd->nr=i;
2363 intd->val=0;
2364 intd->incr=0;
2365 intd->next=intdef;
2366 intdef=intd;
2368 while (*c==' ' || *c=='\t') c++;
2369 c=scan_expression(c,&intd->val);
2370 if (*c!='\n') {
2371 while (*c==' ' || *c=='\t') c++;
2372 c=scan_expression(c,&intd->incr);
2374 c=skip_till_newline(c);
2375 break;
2377 case V('a','m'):
2378 /* .am xx yy : append to a macro. */
2379 /* define or handle as .ig yy */
2380 mode=1;
2381 case V('d','e'):
2382 /* .de xx yy : define or redefine macro xx; end at .yy (..) */
2383 /* define or handle as .ig yy */
2385 STRDEF *de;
2386 int olen=0;
2387 c=c+j;
2388 sl=fill_words(c, wordlist, &words);
2389 i=V(c[0],c[1]);j=2;
2390 if (words==1) wordlist[1]=".."; else {
2391 wordlist[1]--;
2392 wordlist[1][0]='.';
2393 j=3;
2395 c=sl+1;
2396 sl=c;
2397 while (*c && strncmp(c,wordlist[1],j)) c=skip_till_newline(c);
2398 de=defdef;
2399 while (de && de->nr!= i) de=de->next;
2400 if (mode && de) olen=strlen(de->st);
2401 j=olen+c-sl;
2402 h= (char*) malloc((j*2+4)*sizeof(char));
2403 if (h) {
2404 for (j=0; j<olen; j++)
2405 h[j]=de->st[j];
2406 if (!j || h[j-1]!='\n')
2407 h[j++]='\n';
2408 while (sl!=c) {
2409 if (sl[0]=='\\' && sl[1]=='\\') {
2410 h[j++]='\\'; sl++;
2411 } else
2412 h[j++]=*sl;
2413 sl++;
2415 h[j]='\0';
2416 if (de) {
2417 if (de->st) free(de->st);
2418 de->st=h;
2419 } else {
2420 de = (STRDEF*) malloc(sizeof(STRDEF));
2421 de->nr=i;
2422 de->next=defdef;
2423 de->st=h;
2424 defdef=de;
2428 c=skip_till_newline(c);
2429 break;
2430 default:
2431 /* search macro database of self-defined macros */
2432 owndef = defdef;
2433 while (owndef && owndef->nr!=i) owndef=owndef->next;
2434 if (owndef) {
2435 char **oldargument;
2436 int deflen;
2437 int onff;
2438 sl=fill_words(c+j, wordlist, &words);
2439 c=sl+1;
2440 *sl='\0';
2441 for (i=1;i<words; i++) wordlist[i][-1]='\0';
2442 for (i=0; i<words; i++) {
2443 char *h=NULL;
2444 scan_troff(wordlist[i],1,&h);
2445 wordlist[i]=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;
2452 argument=wordlist;
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]);
2458 *sl='\n';
2459 } else
2460 c=skip_till_newline(c);
2461 break;
2464 if (fillout) { out_html(NEWLINE); curpos++; }
2465 NEWLINE[0]='\n';
2466 return c;
2469 void flush(void)
2473 static int contained_tab=0;
2475 char *scan_troff(char *c, int san, char **result)
2476 { /* san : stop at newline */
2477 char *h;
2478 char intbuff[500];
2479 int ibp=0;
2480 #define FLUSHIBP if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
2481 char *exbuffer;
2482 int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun;
2483 int usenbsp=0;
2485 exbuffer=buffer;
2486 exbuffpos=buffpos;
2487 exbuffmax=buffmax;
2488 exnewline_for_fun=newline_for_fun;
2489 exscaninbuff=scaninbuff;
2490 newline_for_fun=0;
2491 if (result) {
2492 if (*result) {
2493 buffer=*result;
2494 buffpos=strlen(buffer);
2495 buffmax=buffpos;
2496 } else {
2497 buffer=(char *) malloc(1000*sizeof(char));
2498 buffpos=0;
2499 buffmax=1000;
2501 scaninbuff=1;
2503 h=c;
2504 /* start scanning */
2505 while (*h && (!san || newline_for_fun || *h!='\n')) {
2506 if (*h==escapesym) {
2507 h++;
2508 FLUSHIBP;
2509 h = scan_escape(h);
2510 } else if (*h==controlsym && h[-1]=='\n') {
2511 h++;
2512 FLUSHIBP;
2513 h = scan_request(h);
2514 if (san && h[-1]=='\n') h--;
2515 } else if (*h==nobreaksym && h[-1]=='\n') {
2516 h++;
2517 FLUSHIBP;
2518 h = scan_request(h);
2519 if (san && h[-1]=='\n') h--;
2520 } else {
2521 if (h[-1]=='\n' && still_dd && isalnum(*h)) {
2522 /* sometimes a .HP request is not followed by a .br request */
2523 FLUSHIBP;
2524 out_html("<DD>");
2525 curpos=0;
2526 still_dd=0;
2528 switch (*h) {
2529 case '&':
2530 intbuff[ibp++]='&';
2531 intbuff[ibp++]='a';
2532 intbuff[ibp++]='m';
2533 intbuff[ibp++]='p';
2534 intbuff[ibp++]=';';
2535 curpos++;
2536 break;
2537 case '<':
2538 intbuff[ibp++]='&';
2539 intbuff[ibp++]='l';
2540 intbuff[ibp++]='t';
2541 intbuff[ibp++]=';';
2542 curpos++;
2543 break;
2544 case '>':
2545 intbuff[ibp++]='&';
2546 intbuff[ibp++]='g';
2547 intbuff[ibp++]='t';
2548 intbuff[ibp++]=';';
2549 curpos++;
2550 break;
2551 case '"':
2552 intbuff[ibp++]='&';
2553 intbuff[ibp++]='q';
2554 intbuff[ibp++]='u';
2555 intbuff[ibp++]='o';
2556 intbuff[ibp++]='t';
2557 intbuff[ibp++]=';';
2558 curpos++;
2559 break;
2560 case '\n':
2561 if (h[-1]=='\n' && fillout) {
2562 intbuff[ibp++]='<';
2563 intbuff[ibp++]='P';
2564 intbuff[ibp++]='>';
2566 if (contained_tab && fillout) {
2567 intbuff[ibp++]='<';
2568 intbuff[ibp++]='B';
2569 intbuff[ibp++]='R';
2570 intbuff[ibp++]='>';
2572 contained_tab=0;
2573 curpos=0;
2574 usenbsp=0;
2575 intbuff[ibp++]='\n';
2576 break;
2577 case '\t':
2579 int curtab=0;
2580 contained_tab=1;
2581 FLUSHIBP;
2582 /* like a typewriter, not like TeX */
2583 tabstops[19]=curpos+1;
2584 while (curtab<maxtstop && tabstops[curtab]<=curpos)
2585 curtab++;
2586 if (curtab<maxtstop) {
2587 if (!fillout) {
2588 while (curpos<tabstops[curtab]) {
2589 intbuff[ibp++]=' ';
2590 if (ibp>480) { FLUSHIBP; }
2591 curpos++;
2593 } else {
2594 out_html("<TT>");
2595 while (curpos<tabstops[curtab]) {
2596 out_html("&nbsp;");
2597 curpos++;
2599 out_html("</TT>");
2603 break;
2604 default:
2605 if (*h==' ' && (h[-1]=='\n' || usenbsp)) {
2606 FLUSHIBP;
2607 if (!usenbsp && fillout) {
2608 out_html("<BR>");
2609 curpos=0;
2611 usenbsp=fillout;
2612 if (usenbsp) out_html("&nbsp;"); else intbuff[ibp++]=' ';
2613 } else if (*h>31 && *h<127) intbuff[ibp++]=*h;
2614 else if (((unsigned char)(*h))>127) {
2615 intbuff[ibp++]='&';
2616 intbuff[ibp++]='#';
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;
2620 intbuff[ibp++]=';';
2622 curpos++;
2623 break;
2625 if (ibp>480) FLUSHIBP;
2626 h++;
2629 FLUSHIBP;
2630 if (buffer) buffer[buffpos]='\0';
2631 if (san && *h) h++;
2632 newline_for_fun=exnewline_for_fun;
2633 if (result) {
2634 *result = buffer;
2635 buffer=exbuffer;
2636 buffpos=exbuffpos;
2637 buffmax=exbuffmax;
2638 scaninbuff=exscaninbuff;
2640 return h;
2643 char *sectionname=NULL;
2644 STRDEF *foundpages=NULL;
2646 int search_manpath_all(char *name)
2648 char smfbuf[1000];
2649 char cmpbuf[100];
2650 int i,j,n,l,nr=0;
2651 DIR *dr;
2652 struct dirent *de;
2653 STRDEF *h=NULL;
2655 strcpy(cmpbuf,name);
2656 n=strlen(name);
2657 cmpbuf[n++]='.';
2658 cmpbuf[n+1]='\0';
2659 for (i=0; manpath[i]; i++) {
2660 strcpy(smfbuf, manpath[i]);
2661 l=strlen(smfbuf);
2662 strcpy(smfbuf+l, "man");
2663 l+=3;
2664 smfbuf[l+1]='\0';
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)) {
2671 int stlen;
2672 if (h) {
2673 h->next=(STRDEF*) malloc(sizeof(STRDEF));
2674 h=h->next;
2675 } else
2676 h=foundpages=(STRDEF*) malloc(sizeof(STRDEF));
2677 h->nr=i*256+j;
2678 stlen=strlen(de->d_name)+1;
2679 h->st=(char*) malloc(stlen*sizeof(char));
2680 nr++;
2681 strcpy(h->st, de->d_name);
2682 h->next=NULL;
2685 closedir(dr);
2689 return nr;
2692 int search_manpath_section(char *name, char* section)
2694 char smfbuf[1000];
2695 char cmpbuf[100];
2696 int i,j,n,l,nr=0;
2697 DIR *dr;
2698 struct dirent *de;
2699 STRDEF *h=NULL;
2701 if (!section) return search_manpath_all(name);
2702 j=0;
2703 while (sections[j] && sections[j]!=section[0]) j++;
2704 if (!sections[j]) return search_manpath_all(name);
2705 strcpy(cmpbuf,name);
2706 n=strlen(name);
2707 cmpbuf[n++]='.';
2708 cmpbuf[n++]=section[0];
2709 cmpbuf[n]='\0';
2710 for (i=0; manpath[i]; i++) {
2711 strcpy(smfbuf, manpath[i]);
2712 l=strlen(smfbuf);
2713 strcpy(smfbuf+l, "man");
2714 l+=3;
2715 smfbuf[l]=section[0];
2716 smfbuf[l+1]='\0';
2717 if ((dr=opendir(smfbuf))) {
2718 while ((de=readdir(dr))) {
2719 if (!strncmp(de->d_name, cmpbuf, n)) {
2720 int stlen;
2721 if (h) {
2722 h->next=(STRDEF*) malloc(sizeof(STRDEF));
2723 h=h->next;
2724 } else
2725 h=foundpages=(STRDEF*) malloc(sizeof(STRDEF));
2726 h->nr=i*256+j;
2727 stlen=strlen(de->d_name)+1;
2728 h->st=(char*) malloc(stlen*sizeof(char));
2729 nr++;
2730 strcpy(h->st, de->d_name);
2731 h->next=NULL;
2734 closedir(dr);
2737 return nr;
2740 static char smfbuf[1000];
2742 char *search_manpath(char *name)
2744 int i;
2745 struct stat stbuf;
2747 for (i=0; manpath[i]; i++) {
2748 strcpy(smfbuf, manpath[i]);
2749 strcat(smfbuf, name);
2750 if (stat(smfbuf, &stbuf) !=-1) return smfbuf;
2752 return NULL;
2755 int main(int argc, char **argv)
2757 FILE *f;
2758 struct stat stbuf;
2759 char *t=NULL;
2760 int l=0,i;char *buf;
2761 int mopt=0;
2762 int notinsection=0;
2763 char *h, *fullname;
2764 STRDEF *stdf;
2766 t = getenv("PATH_INFO");
2767 if (!t || !*t) /* not : cgi/man2html/mani/name.i */ {
2768 i=1;
2769 while (i<argc) {
2770 switch (argv[i][0]) {
2771 case '-':
2772 if (argv[i][1]=='M') {
2773 mopt=1;
2774 if (i+1<argc) {
2775 char *s1, *s2;
2776 i++;
2777 l=strlen(argv[i]);
2778 manpath[0]=(char*) malloc(l+2);
2779 s1=manpath[0];
2780 s2=argv[i];
2781 while ((*s1=*s2)) {
2782 if (*s2=='%') {
2783 s2++;
2784 *s1=0;
2785 if (isdigit(*s2)) *s1=*s2-'0'; else
2786 *s1=tolower(*s2)-'a'+10;
2787 s2++;*s1=(*s1)*16;
2788 if (isdigit(*s2)) *s1=*s1+*s2-'0'; else
2789 *s1=*s1+tolower(*s2)-'a'+10;
2791 s1++;
2792 s2++;
2794 if (s1[-1]!='/') { *s1++='/';*s1='\0'; }
2797 break;
2798 case '1': case '2': case '3': case '4': case '5': case '6':
2799 case '7': case '8': case '9': case 'n': case 'l':
2800 if (!argv[i][1]) {
2801 sectionname=argv[i];
2802 break;
2803 } else
2804 if (!argv[i][2] && isalpha(argv[i][1]) &&
2805 !isalpha(argv[i][0]) && islower(argv[i][1])) {
2806 sectionname=argv[i];
2807 break;
2809 default:
2810 if (argv[i][0])
2811 t=argv[i];
2812 break;
2814 i++;
2816 if (t) {
2817 char *s1, *s2;
2818 i++;
2819 l=strlen(t)+1;
2820 s2=t;
2821 t=s1=(char*) malloc(l);
2822 while ((*s1=*s2)) {
2823 if (*s2=='%') {
2824 s2++;
2825 *s1=0;
2826 if (isdigit(*s2)) *s1=*s2-'0'; else
2827 *s1=tolower(*s2)-'a'+10;
2828 s2++;*s1=(*s1)*16;
2829 if (isdigit(*s2)) *s1=*s1+*s2-'0'; else
2830 *s1=*s1+tolower(*s2)-'a'+10;
2832 s1++;
2833 s2++;
2837 if (!t || !*t) usage();
2838 i=0;
2839 h=t;
2840 while (*h) i=i+(*h++ == '/');
2841 if (i==0) {
2842 if (sectionname) {
2843 char fname[1000];
2844 sprintf(fname, "man%c/%s.%s", sectionname[0],t,sectionname);
2845 h=search_manpath(fname);
2846 if (h) {
2847 printf("Location: " CGIBASE "%s\n\n", h);
2848 exit(0);
2849 } else {
2850 if (sectionname[1]) fname[strlen(fname)-1]='\0';
2851 i=search_manpath_section(t,sectionname);
2852 notinsection=(i>0);
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],
2860 foundpages->st);
2861 exit(0);
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]:' '));
2868 if (!i)
2869 printf("Sorry, no manpages available for %s.\n", t);
2870 else {
2871 STRDEF *strd;
2872 printf("<UL>\n");
2873 strd=foundpages;
2874 while (strd) {
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]);
2879 strd=strd->next;
2881 printf("</UL>\n");
2883 printf("</BODY></HTML>\n");
2884 exit(0);
2886 printf("Content-type: text/html\n\n");
2887 h=strstr(t, "man");
2888 if (!h) {
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);
2895 exit(0);
2897 h=strstr(t,"/../");
2898 if (h) {
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");
2906 exit(0);
2908 h=search_manpath(t);
2909 if (!h && i>2) {
2910 char *g;
2911 g=strrchr(t,'/');
2912 *g='.';
2913 h=strrchr(t,'/');
2914 *g='/';
2915 h=search_manpath(h);
2917 if (!h) {
2918 h=strrchr(t,'.');
2919 if (h) {
2920 *h='\0';
2921 sectionname=h+1;
2922 } else sectionname=NULL;
2923 h=strrchr(t,'/');
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);
2931 if (!i) {
2932 if (sectionname)
2933 printf(",nor in any other section.\n");
2934 else
2935 printf("in any section.\n");
2936 printf("<HR>\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");
2940 } else {
2941 STRDEF *strd;
2942 printf(".\nMaybe you can use %s instead.\n<UL>\n",
2943 (i>1?"one of the following pages":"this page"));
2944 strd=foundpages;
2945 while (strd) {
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]);
2950 strd=strd->next;
2952 printf("</UL>\n");
2954 printf("</BODY></HTML>\n");
2955 exit(0);
2957 fullname=h;
2958 t=strrchr(h,'/');
2959 if (t) {
2960 *t='\0';
2961 if (!chdir(h))
2962 h=t+1;
2963 *t='/';
2965 if (stat(h, &stbuf)!=-1) l=stbuf.st_size;
2966 buf = (char*) malloc((l+5)*sizeof(char));
2967 f=fopen(h,"r");
2968 if (!f || !buf || !l) {
2969 t=strrchr(h,'.');
2970 if (t) *t='\0';
2971 t=strrchr(h,'/');
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);
2977 exit(0);
2979 i=fread(buf+1,1,l,f);
2980 fclose(f);
2981 fname=h;
2982 #ifdef MAKEINDEX
2983 idxfile=fopen(INDEXFILE, "a");
2984 #endif
2985 stdf=&standardchar[0];
2986 i=0;
2987 while (stdf->nr) {
2988 stdf->next=&standardchar[i];
2989 stdf=stdf->next;
2990 i++;
2992 chardef=&standardchar[0];
2993 stdf=&standardstring[0];
2994 i=0;
2995 while (stdf->nr) {
2996 stdf->next=&standardstring[i];
2997 stdf=stdf->next;
2998 i++;
3000 strdef=&standardstring[0];
3001 intdef=&standardint[0];
3002 i=0;
3003 while (intdef->nr) {
3004 intdef->next=&standardint[i];
3005 intdef=intdef->next;
3006 i++;
3008 intdef=&standardint[0];
3009 defdef=NULL;
3010 buf[0]='\n';
3011 buf[l]='\n';
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;
3017 else itemdepth--;
3019 out_html(change_to_font(0));
3020 out_html(change_to_size(0));
3021 if (!fillout) {
3022 fillout=1;
3023 out_html("</PRE>");
3025 out_html(NEWLINE);
3026 if (output_possible) {
3027 /* &nbsp; for mosaic users */
3028 printf("<HR>\n<A NAME=\"index\">&nbsp;</A><H2>Index</H2>\n<DL>\n");
3029 manidx[mip]=0;
3030 printf(manidx);
3031 if (subs) printf("</DL>\n");
3032 printf("</DL>\n");
3033 print_sig();
3034 printf("</BODY>\n</HTML>\n");
3035 } else {
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",
3045 fullname);
3046 print_sig();
3047 printf("</BODY>\n</HTML>\n");
3049 #ifdef MAKEINDEX
3050 if (idxfile) fclose(idxfile);
3051 #endif
3052 if (buf) free(buf);
3053 return 0;