xref: /inferno-os/appl/lib/man.b (revision 7d5a2526f46cd3474fb96a684f7b87e9e78128b0)
1implement Man;
2
3include "sys.m";
4	sys: Sys;
5include "filepat.m";
6include "bufio.m";
7include "man.m";
8
9MANPATH: con "/man/";
10PATHDEPTH: con 1;
11
12indices: list of (string, list of (string, string));
13
14loadsections(scanlist: list of string): string
15{
16	sys = load Sys Sys->PATH;
17	bufio := load Bufio Bufio->PATH;
18	Iobuf: import bufio;
19
20	if (bufio == nil)
21		return sys->sprint("cannot load %s: %r", Bufio->PATH);
22
23	indexpaths: list of string;
24	if (scanlist == nil) {
25		filepat := load Filepat Filepat->PATH;
26		if (filepat == nil)
27			return sys->sprint("cannot load %s: %r", Filepat->PATH);
28
29		indexpaths = filepat->expand(MANPATH + "[0-9]*/INDEX");
30		if (indexpaths == nil)
31			return "cannot find man pages";
32	} else {
33		for (; scanlist != nil; scanlist = tl scanlist)
34			indexpaths = MANPATH + trimdot(hd scanlist) + "/INDEX" :: indexpaths;
35		indexpaths = sortuniq(indexpaths);
36	}
37
38	sections: list of string;
39	for (; indexpaths != nil; indexpaths = tl indexpaths) {
40		path := hd indexpaths;
41		(nil, toks) := sys->tokenize(path, "/");
42		for (d := 0; d < PATHDEPTH; d++)
43			toks = tl toks;
44		sections = hd toks :: sections;
45	}
46
47	for (sl := sections; sl != nil; sl = tl sl) {
48		section := hd sl;
49		path := MANPATH + section + "/INDEX";
50		iob := bufio->open(path, Sys->OREAD);
51		if (iob == nil)
52			continue;
53		pairs: list of (string, string) = nil;
54
55		while((s := iob.gets('\n')) != nil) {
56			if (s[len s - 1] == '\n')
57				s = s[0:len s - 1];
58			(n, toks) := sys->tokenize(s, " ");
59			if (n != 2)
60				continue;
61			pairs = (hd toks, hd tl toks) :: pairs;
62		}
63		iob.close();
64		indices = (section, pairs) :: indices;
65	}
66	return nil;
67}
68
69trimdot(s: string): string
70{
71	for(i := 0; i < len s; i++)
72		if(s[i] == '.')
73			return s[0: i];
74	return s;
75}
76
77getfiles(sections: list of string, keys: list of string): list of (int, string, string)
78{
79	ixl: list of (string, list of (string, string));
80
81	if (sections == nil)
82		ixl = indices;
83	else {
84		for (; sections != nil; sections = tl sections) {
85			section := trimdot(hd sections);
86			for (il := indices; il != nil; il = tl il) {
87				(s, mapl) := hd il;
88				if (s == section) {
89					ixl = (s, mapl) :: ixl;
90					break;
91				}
92			}
93		}
94	}
95	paths: list of (int, string, string);
96	for(keyl := keys; keyl != nil; keyl = tl keyl){
97		for (; ixl != nil; ixl = tl ixl) {
98			for ((s, mapl) := hd ixl; mapl != nil; mapl = tl mapl) {
99				(kw, file) := hd mapl;
100				if (hd keyl == kw) {
101					p := MANPATH + trimdot(s) + "/" + file;
102					paths = (int s, kw, p) :: paths;
103				}
104			}
105			# allow files not in the index
106			if(paths == nil || (hd paths).t0 != int s || (hd paths).t1 != hd keyl){
107				p := MANPATH + string int s + "/" + hd keyl;
108				if(sys->stat(p).t0 != -1)
109					paths = (int s, hd keyl, p) :: paths;
110			}
111		}
112	}
113	return paths;
114}
115
116sortuniq(strlist: list of string): list of string
117{
118	strs := array [len strlist] of string;
119	for (i := 0; strlist != nil; (i, strlist) = (i+1, tl strlist))
120		strs[i] = hd strlist;
121
122	# simple sort (greatest first)
123	for (i = 0; i < len strs - 1; i++) {
124		for (j := i+1; j < len strs; j++)
125			if (strs[i] < strs[j])
126				(strs[i], strs[j]) = (strs[j], strs[i]);
127	}
128
129	# construct list (result is ascending)
130	r: list of string;
131	prev := "";
132	for (i = 0; i < len strs; i++) {
133		if (strs[i] != prev) {
134			r = strs[i] :: r;
135			prev = strs[i];
136		}
137	}
138	return r;
139}
140