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