1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#define FOR_man
30#include <toys.h>
31
32GLOBALS(
33 char *M, *k;
34
35 char any, cell, ex, *f, k_done, *line, *m, **sct, **scts, **sufs;
36 regex_t reg;
37)
38
39static void newln()
40{
41 if (FLAG(k)) return;
42 if (TT.any) putchar('\n');
43 if (TT.any && TT.cell != 2) putchar('\n');
44 TT.any = TT.cell = 0;
45}
46
47static void put(char *x)
48{
49 while (*x && (TT.ex || *x != '\n')) TT.any = putchar(*x++);
50}
51
52
53static void s(char *x, char *y)
54{
55 int i = strlen(x), j = strlen(y), k, l;
56
57 for (k = 0; TT.line[k]; k++) if (!strncmp(x, &TT.line[k], i)) {
58 memmove(&TT.line[k], y, j);
59 for (l = k += j; TT.line[l]; l++) TT.line[l] = TT.line[l + i - j];
60 k--;
61 }
62}
63
64static char start(char *x)
65{
66 return !strncmp(x, TT.line, strlen(x));
67}
68
69static void trim(char *x)
70{
71 if (start(x)) while (*x++) TT.line++;
72}
73
74static char k(char *s) {
75 TT.k_done = 2;
76 if (s) TT.line = s;
77 return !regexec(&TT.reg, TT.k, 0, 0, 0)||!regexec(&TT.reg, TT.line, 0, 0, 0);
78}
79
80static void do_man(char **pline, long len)
81{
82 if (!pline) return newln();
83 TT.line = *pline;
84
85 if (FLAG(k)) {
86 if (!TT.k_done && !start(".") && !start("'") && k(strstr(*pline, "- ")))
87 printf("%-20s %s%s", TT.k, "- "+2*(TT.line!=*pline), TT.line);
88 else if (!TT.k_done && start(".so") && k(basename(*pline + 4)))
89 printf("%s - See %s", TT.k, TT.line);
90 } else {
91 s("\\fB", ""), s("\\fI", ""), s("\\fP", ""), s("\\fR", "");
92 s("\\(aq", "'"), s("\\(cq", "'"), s("\\(dq", "\"");
93 s("\\*(lq", "\""), s("\\*(rq", "\"");
94 s("\\(bu", "*"), s("\\(bv", "|");
95 s("\\&", ""), s("\\f(CW", "");
96 s("\\-", "-"), s("\\(", ""), s("\\^", ""), s("\\e", "\\");
97 s("\\*(", "#");
98
99 if (start(".BR")) trim(".BR "), s(" ", "");
100 if (start(".IP")) newln(), trim(".IP ");
101 if (start(".IR")) trim(".IR "), s(" ", "");
102
103 trim(".B ");
104 trim(".BI ");
105 trim(".FN ");
106 trim(".I ");
107 trim(".if n ");
108 if (start(".E")) TT.ex = TT.line[2] == 'X';
109 else if (start(".PP")) newln();
110 else if (start(".SM"));
111 else if (start(".S")) newln(), put(TT.line + 4), newln();
112 else if (start(".so")) put("See "), put(basename(TT.line + 4));
113 else if (start(".TH")) s("\"", " "), put(TT.line + 4);
114 else if (start(".TP")) newln(), TT.cell = 1;
115 else if (start(".") || start("\'"));
116 else if (!*TT.line);
117 else {
118 if (TT.cell) TT.cell++;
119 if (!TT.ex) put(" ");
120 put(TT.line);
121 }
122 }
123}
124
125
126static int zopen(char *s)
127{
128 int fds[] = {-1, -1};
129 char **known = TT.sufs, *suf = strrchr(s, '.');
130
131 if ((*fds = open(s, O_RDONLY)) == -1) return -1;
132 while (suf && *known && strcmp(suf, *known++));
133 if (!suf || !*known) return *fds;
134 sprintf(toybuf, "%czcat"+2*(suf[1]=='g'), suf[1]);
135 xpopen_both((char *[]){toybuf, s, 0}, fds);
136 close(fds[0]);
137 return fds[1];
138}
139
140static char manpath()
141{
142 if (*++TT.sct) return 0;
143 if (!(TT.m = strsep(&TT.M, ":"))) return 1;
144 TT.sct = TT.scts;
145 return 0;
146}
147
148
149static int tryfile(char *name)
150{
151 int dotnum, fd = -1;
152 char *s = xmprintf("%s/man%s/%s.%s.bz2", TT.m, *TT.sct, name, *TT.sct), **suf;
153 size_t len = strlen(s) - 4;
154
155 for (dotnum = 0; dotnum <= 2; dotnum += 2) {
156 suf = TT.sufs;
157 while ((fd == -1) && *suf) strcpy(s + len - dotnum, *suf++), fd = zopen(s);
158
159 }
160 free(s);
161 return fd;
162}
163
164void man_main(void)
165{
166 int fd = -1;
167 TT.scts = (char *[]) {"1", "8", "3", "2", "5", "4", "6", "7", 0};
168 TT.sct = TT.scts - 1;
169 TT.sufs = (char *[]) {".bz2", ".gz", ".xz", "", 0};
170
171 if (!TT.M) TT.M = getenv("MANPATH");
172 if (!TT.M) TT.M = "/usr/share/man";
173
174 if (FLAG(k)) {
175 char *d, *f;
176 DIR *dp;
177 struct dirent *entry;
178
179 xregcomp(&TT.reg, TT.k, REG_ICASE|REG_NOSUB);
180 while (!manpath()) {
181 d = xmprintf("%s/man%s", TT.m, *TT.sct);
182 if (!(dp = opendir(d))) continue;
183 while ((entry = readdir(dp))) {
184 if (entry->d_name[0] == '.') continue;
185 f = xmprintf("%s/%s", d, TT.k = entry->d_name);
186 if (-1 != (fd = zopen(f))) {
187 TT.k_done = 0;
188 do_lines(fd, '\n', do_man);
189 }
190 free(f);
191 }
192 closedir(dp);
193 free(d);
194 }
195 return regfree(&TT.reg);
196 }
197
198 if (!toys.optc) help_exit("which page?");
199
200 if (toys.optc == 1) {
201 if (strchr(*toys.optargs, '/')) fd = zopen(*toys.optargs);
202 else while ((fd == -1) && !manpath()) fd = tryfile(*toys.optargs);
203 if (fd == -1) error_exit("no %s", *toys.optargs);
204
205
206 } else {
207 TT.scts = (char *[]){*toys.optargs, 0}, TT.sct = TT.scts - 1;
208 while ((fd == -1) && !manpath()) fd = tryfile(toys.optargs[1]);
209 if (fd == -1) error_exit("section %s no %s", *--TT.sct, toys.optargs[1]);
210 }
211
212 do_lines(fd, '\n', do_man);
213}
214