📄 man2html.c
字号:
/* * This program was written by Richard Verhoeven (NL:5482ZX35) * at the Eindhoven University of Technology. Email: rcb5@win.tue.nl * * Permission is granted to distribute, modify and use this program as long * as this comment is not removed or changed. * * THIS IS A MODIFIED VERSION. IT WAS MODIFIED BY chet@po.cwru.edu FOR * USE BY BASH. *//* * man2html will add links to the converted manpages. The function add_links * is used for that. At the moment it will add links as follows, where * indicates what should match to start with: * ^^^ * Recognition Item Link * ---------------------------------------------------------- * name(*) Manpage ../man?/name.* * ^ * name@hostname Email address mailto:name@hostname * ^ * method://string URL method://string * ^^^ * www.host.name WWW server http://www.host.name * ^^^^ * ftp.host.name FTP server ftp://ftp.host.name * ^^^^ * <file.h> Include file file:/usr/include/file.h * ^^^ * * Since man2html does not check if manpages, hosts or email addresses exist, * some links might not work. For manpages, some extra checks are performed * to make sure not every () pair creates a link. Also out of date pages * might point to incorrect places. * * The program will not allow users to get system specific files, such as * /etc/passwd. It will check that "man" is part of the specified file and * that "/../" isn't. Even if someone manages to get such file, man2html will * handle it like a manpage and will usually not produce any output (or crash). * * If you find any bugs when normal manpages are converted, please report * them to me (rcb5@win.tue.nl) after you have checked that man(1) can handle * the manpage correct. * * Known bugs and missing features: * * * Equations are not converted at all. * * Tables are converted but some features are not possible in html. * * The tabbing environment is converted by counting characters and adding * spaces. This might go wrong (outside <PRE>) * * Some pages look beter if man2html works in troff mode, especially pages * with tables. You can deside at compile time which made you want to use. * * -DNROFF=0 troff mode * -DNROFF=1 nroff mode (default) * * if you install both modes, you should compile with the correct CGIBASE. * * Some manpages rely on the fact that troff/nroff is used to convert * them and use features which are not descripted in the man manpages. * (definitions, calculations, conditionals, requests). I can't guarantee * that all these features work on all manpages. (I didn't have the * time to look through all the available manpages.) */#ifdef HAVE_CONFIG_H#include <config.h>#endif#define NROFF 0#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <ctype.h>#include <sys/types.h>#include <time.h>#include <sys/time.h>#include <errno.h>#define NULL_TERMINATED(n) ((n) + 1)#define HUGE_STR_MAX 10000#define LARGE_STR_MAX 2000#define MED_STR_MAX 500#define SMALL_STR_MAX 100#define TINY_STR_MAX 10#define MAX_MAN_PATHS 100 /* Max number of directories */#define MAX_ZCATS 10 /* Max number of zcat style programs */#define MAX_WORDLIST 100#ifndef EXIT_SUCCESS#define EXIT_SUCCESS 0#endif#ifndef EXIT_FAILURE#define EXIT_FAILURE 1#endif#ifndef EXIT_USAGE#define EXIT_USAGE 2#endifstatic char location_base[NULL_TERMINATED(MED_STR_MAX)] = "";static char th_page_and_sec[128] = { '\0' };static char th_datestr[128] = { '\0' };static char th_version[128] = { '\0' };char *signature = "<HR>\nThis document was created by man2html from %s.<BR>\nTime: %s\n";/* timeformat for signature */#define TIMEFORMAT "%d %B %Y %T %Z"char *manpage;/* BSD mandoc Bl/El lists to HTML list types */#define BL_DESC_LIST 1#define BL_BULLET_LIST 2#define BL_ENUM_LIST 4/* BSD mandoc Bd/Ed example(?) blocks */#define BD_LITERAL 1#define BD_INDENT 2#ifndef HAVE_STRERRORstatic char *strerror(int e){ static char emsg[40];#if defined (HAVE_SYS_ERRLIST) extern int sys_nerr; extern char *sys_errlist[]; if (e > 0 && e < sys_nerr) return (sys_errlist[e]); else#endif /* HAVE_SYS_ERRLIST */ { sprintf(emsg, "Unknown system error %d", e); return (&emsg[0]); }}#endif /* !HAVE_STRERROR */static char *strgrow(char *old, int len){ char *new = realloc(old, (strlen(old) + len + 1) * sizeof(char)); if (!new) { fprintf(stderr, "man2html: out of memory"); exit(EXIT_FAILURE); } return new;}static char *stralloc(int len){ /* allocate enough for len + NULL */ char *new = malloc((len + 1) * sizeof(char)); if (!new) { fprintf(stderr, "man2html: out of memory"); exit(EXIT_FAILURE); } return new;}/* * Some systems don't have strdup so lets use our own - which can also * check for out of memory. */static char *strduplicate(char *from){ char *new = stralloc(strlen(from)); strcpy(new, from); return new;}/* Assumes space for n plus a null */static char *strmaxcpy(char *to, char *from, int n){ int len = strlen(from); strncpy(to, from, n); to[(len <= n) ? len : n] = '\0'; return to;}static char *strmaxcat(char *to, char *from, int n){ int to_len = strlen(to); if (to_len < n) { int from_len = strlen(from); int cp = (to_len + from_len <= n) ? from_len : n - to_len; strncpy(to + to_len, from, cp); to[to_len + cp] = '\0'; } return to;}/* Assumes space for limit plus a null */static char *strlimitcpy(char *to, char *from, int n, int limit){ int len = n > limit ? limit : n; strmaxcpy(to, from, len); to[len] = '\0'; return to;}/* * takes string and escapes all metacharacters. should be used before * including string in system() or similar call. */static char *escape_input(char *str){ int i, j = 0; static char new[NULL_TERMINATED(MED_STR_MAX)]; if (strlen(str) * 2 + 1 > MED_STR_MAX) { fprintf(stderr, "man2html: escape_input - str too long:\n%-80s...\n", str); exit(EXIT_FAILURE); } for (i = 0; i < strlen(str); i++) { if (!(((str[i] >= 'A') && (str[i] <= 'Z')) || ((str[i] >= 'a') && (str[i] <= 'z')) || ((str[i] >= '0') && (str[i] <= '9')))) { new[j] = '\\'; j++; } new[j] = str[i]; j++; } new[j] = '\0'; return new;}static voidusage(void){ fprintf(stderr, "man2html: usage: man2html filename\n");}/* * below this you should not change anything unless you know a lot * about this program or about troff. */typedef struct STRDEF STRDEF;struct STRDEF { int nr, slen; char *st; STRDEF *next;};typedef struct INTDEF INTDEF;struct INTDEF { int nr; int val; int incr; INTDEF *next;};static char NEWLINE[2] = "\n";static char idxlabel[6] = "ixAAA";#define INDEXFILE "/tmp/manindex.list"static char *fname;static FILE *idxfile;static STRDEF *chardef, *strdef, *defdef;static INTDEF *intdef;#define V(A,B) ((A)*256+(B))static INTDEF standardint[] = { {V('n', ' '), NROFF, 0, NULL}, {V('t', ' '), 1 - NROFF, 0, NULL}, {V('o', ' '), 1, 0, NULL}, {V('e', ' '), 0, 0, NULL}, {V('.', 'l'), 70, 0, NULL}, {V('.', '$'), 0, 0, NULL}, {V('.', 'A'), NROFF, 0, NULL}, {V('.', 'T'), 1 - NROFF, 0, NULL}, {V('.', 'V'), 1, 0, NULL}, /* the me package tests for this */{0, 0, 0, NULL}};static STRDEF standardstring[] = { {V('R', ' '), 1, "®", NULL}, {V('l', 'q'), 2, "``", NULL}, {V('r', 'q'), 2, "''", NULL}, {0, 0, NULL, NULL}};static STRDEF standardchar[] = { {V('*', '*'), 1, "*", NULL}, {V('*', 'A'), 1, "A", NULL}, {V('*', 'B'), 1, "B", NULL}, {V('*', 'C'), 2, "Xi", NULL}, {V('*', 'D'), 5, "Delta", NULL}, {V('*', 'E'), 1, "E", NULL}, {V('*', 'F'), 3, "Phi", NULL}, {V('*', 'G'), 5, "Gamma", NULL}, {V('*', 'H'), 5, "Theta", NULL}, {V('*', 'I'), 1, "I", NULL}, {V('*', 'K'), 1, "K", NULL}, {V('*', 'L'), 6, "Lambda", NULL}, {V('*', 'M'), 1, "M", NULL}, {V('*', 'N'), 1, "N", NULL}, {V('*', 'O'), 1, "O", NULL}, {V('*', 'P'), 2, "Pi", NULL}, {V('*', 'Q'), 3, "Psi", NULL}, {V('*', 'R'), 1, "P", NULL}, {V('*', 'S'), 5, "Sigma", NULL}, {V('*', 'T'), 1, "T", NULL}, {V('*', 'U'), 1, "Y", NULL}, {V('*', 'W'), 5, "Omega", NULL}, {V('*', 'X'), 1, "X", NULL}, {V('*', 'Y'), 1, "H", NULL}, {V('*', 'Z'), 1, "Z", NULL}, {V('*', 'a'), 5, "alpha", NULL}, {V('*', 'b'), 4, "beta", NULL}, {V('*', 'c'), 2, "xi", NULL}, {V('*', 'd'), 5, "delta", NULL}, {V('*', 'e'), 7, "epsilon", NULL}, {V('*', 'f'), 3, "phi", NULL}, {V('*', 'g'), 5, "gamma", NULL}, {V('*', 'h'), 5, "theta", NULL}, {V('*', 'i'), 4, "iota", NULL}, {V('*', 'k'), 5, "kappa", NULL}, {V('*', 'l'), 6, "lambda", NULL}, {V('*', 'm'), 1, "µ", NULL}, {V('*', 'n'), 2, "nu", NULL}, {V('*', 'o'), 1, "o", NULL}, {V('*', 'p'), 2, "pi", NULL}, {V('*', 'q'), 3, "psi", NULL}, {V('*', 'r'), 3, "rho", NULL}, {V('*', 's'), 5, "sigma", NULL}, {V('*', 't'), 3, "tau", NULL}, {V('*', 'u'), 7, "upsilon", NULL}, {V('*', 'w'), 5, "omega", NULL}, {V('*', 'x'), 3, "chi", NULL}, {V('*', 'y'), 3, "eta", NULL}, {V('*', 'z'), 4, "zeta", NULL}, {V('t', 's'), 5, "sigma", NULL}, {V('+', '-'), 1, "±", NULL}, {V('1', '2'), 1, "½", NULL}, {V('1', '4'), 1, "¼", NULL}, {V('3', '4'), 1, "¾", NULL}, {V('F', 'i'), 3, "ffi", NULL}, {V('F', 'l'), 3, "ffl", NULL}, {V('a', 'a'), 1, "´", NULL}, {V('a', 'p'), 1, "~", NULL}, {V('b', 'r'), 1, "|", NULL}, {V('b', 'u'), 1, "*", NULL}, {V('b', 'v'), 1, "|", NULL}, {V('c', 'i'), 1, "o", NULL}, {V('c', 'o'), 1, "©", NULL}, {V('c', 't'), 1, "¢", NULL}, {V('d', 'e'), 1, "°", NULL}, {V('d', 'g'), 1, "+", NULL}, {V('d', 'i'), 1, "÷", NULL}, {V('e', 'm'), 1, "-", NULL}, {V('e', 'm'), 3, "---", NULL}, {V('e', 'q'), 1, "=", NULL}, {V('e', 's'), 1, "Ø", NULL}, {V('f', 'f'), 2, "ff", NULL}, {V('f', 'i'), 2, "fi", NULL}, {V('f', 'l'), 2, "fl", NULL}, {V('f', 'm'), 1, "´", NULL}, {V('g', 'a'), 1, "`", NULL}, {V('h', 'y'), 1, "-", NULL}, {V('l', 'c'), 2, "|¯", NULL}, {V('l', 'f'), 2, "|_", NULL}, {V('l', 'k'), 1, "<FONT SIZE=+2>{</FONT>", NULL}, {V('m', 'i'), 1, "-", NULL}, {V('m', 'u'), 1, "×", NULL}, {V('n', 'o'), 1, "¬", NULL}, {V('o', 'r'), 1, "|", NULL}, {V('p', 'l'), 1, "+", NULL}, {V('r', 'c'), 2, "¯|", NULL}, {V('r', 'f'), 2, "_|", NULL}, {V('r', 'g'), 1, "®", NULL}, {V('r', 'k'), 1, "<FONT SIZE=+2>}</FONT>", NULL}, {V('r', 'n'), 1, "¯", NULL}, {V('r', 'u'), 1, "_", NULL}, {V('s', 'c'), 1, "§", NULL}, {V('s', 'l'), 1, "/", NULL}, {V('s', 'q'), 2, "[]", NULL}, {V('u', 'l'), 1, "_", NULL}, {0, 0, NULL, NULL}};/* default: print code */static char eqndelimopen = 0, eqndelimclose = 0;static char escapesym = '\\', nobreaksym = '\'', controlsym = '.', fieldsym = 0, padsym = 0;static char *buffer = NULL;static int buffpos = 0, buffmax = 0;static int scaninbuff = 0;static int itemdepth = 0;static int dl_set[20] = {0};static int still_dd = 0;static int tabstops[20] = {8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96};static int maxtstop = 12;static int curpos = 0;static char *scan_troff(char *c, int san, char **result);static char *scan_troff_mandoc(char *c, int san, char **result);static char **argument = NULL;static char charb[TINY_STR_MAX];static voidprint_sig(void){ char datbuf[NULL_TERMINATED(MED_STR_MAX)]; struct tm *timetm; time_t clock; datbuf[0] = '\0'; clock = time(NULL); timetm = localtime(&clock); strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); printf(signature, manpage, datbuf);}static char *expand_char(int nr){ STRDEF *h; h = chardef; if (!nr) return NULL; while (h) if (h->nr == nr) { curpos += h->slen; return h->st; } else h = h->next; charb[0] = nr / 256; charb[1] = nr % 256; charb[2] = '\0'; if (charb[0] == '<') { /* Fix up <= */ charb[4] = charb[1]; strncpy(charb, "<", 4); charb[5] = '\0'; } curpos += 2; return charb;}static char *expand_string(int nr){ STRDEF *h = strdef; if (!nr) return NULL; while (h) if (h->nr == nr) { curpos += h->slen; return h->st; } else h = h->next; return NULL;}static char *read_man_page(char *filename){ char *man_buf = NULL; int i; FILE *man_stream = NULL; struct stat stbuf; int buf_size; if (stat(filename, &stbuf) == -1) return NULL; buf_size = stbuf.st_size; man_buf = stralloc(buf_size + 5); man_stream = fopen(filename, "r"); if (man_stream) { man_buf[0] = '\n'; if (fread(man_buf + 1, 1, buf_size, man_stream) == buf_size) { man_buf[buf_size] = '\n'; man_buf[buf_size + 1] = man_buf[buf_size + 2] = '\0'; } else { man_buf = NULL; } fclose(man_stream); } return man_buf;}static char outbuffer[NULL_TERMINATED(HUGE_STR_MAX)];static int obp = 0;static int no_newline_output = 0;static int newline_for_fun = 0;static int output_possible = 0;static int out_length = 0;/* * Add the links to the output. At the moment the following are * recognized: * #if 0 * name(*) -> ../man?/name.*#endif * method://string -> method://string * www.host.name -> http://www.host.name * ftp.host.name -> ftp://ftp.host.name * name@host -> mailto:name@host * <name.h> -> file:/usr/include/name.h (guess) * * Other possible links to add in the future: * * /dir/dir/file -> file:/dir/dir/file */static voidadd_links(char *c){ int i, j, nr; char *f, *g, *h; char *idtest[6]; /* url, mailto, www, ftp, manpage */ out_length += strlen(c); /* search for (section) */ nr = 0; idtest[0] = strstr(c + 1, "://"); idtest[1] = strchr(c + 1, '@'); idtest[2] = strstr(c, "www."); idtest[3] = strstr(c, "ftp.");#if 0 idtest[4] = strchr(c + 1, '(');#else idtest[4] = 0;#endif idtest[5] = strstr(c + 1, ".h>"); for (i = 0; i < 6; i++) nr += (idtest[i] != NULL); while (nr) { j = -1; for (i = 0; i < 6; i++) if (idtest[i] && (j < 0 || idtest[i] < idtest[j])) j = i; switch (j) { case 5: /* <name.h> */ f = idtest[5]; h = f + 2; g = f; while (g > c && g[-1] != ';') g--; if (g != c) { char t; t = *g; *g = '\0'; fputs(c, stdout); *g = t; *h = '\0'; printf("<A HREF=\"file:/usr/include/%s\">%s</A>>", g, g); c = f + 6; } else { f[5] = '\0'; fputs(c, stdout); f[5] = ';'; c = f + 5; } break; case 4: /* manpage */#if 0 f = idtest[j]; /* check section */ g = strchr(f, ')'); if (g && f - g < 6 && (isalnum(f[-1]) || f[-1] == '>') && ((isdigit(f[1]) && f[1] != '0' && (f[2] == ')' || (isalpha(f[2]) && f[3] == ')') || f[2] == 'X')) || (f[2] == ')' && (f[1] == 'n' || f[1] == 'l')))) { /* this might be a link */ h = f - 1; /* skip html makeup */ while (h > c && *h == '>') { while (h != c && *h != '<') h--; if (h != c) h--; } if (isalnum(*h)) { char t, sec, subsec, *e; e = h + 1; sec = f[1]; subsec = f[2]; if ((subsec == 'X' && f[3] != ')') || subsec == ')') subsec = '\0'; while (h > c && (isalnum(h[-1]) || h[-1] == '_' || h[-1] == '-' || h[-1] == '.')) h--; t = *h; *h = '\0'; fputs(c, stdout); *h = t; t = *e; *e = '\0'; if (subsec) printf("<A HREF=\"" CGIBASE "?man%c/%s.%c%c\">%s</A>", sec, h, sec, tolower(subsec), h); else printf("<A HREF=\"" CGIBASE "?man%c/%s.%c\">%s</A>", sec, h, sec, h); *e = t; c = e;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -