1implement Mc; 2 3include "sys.m"; 4 sys: Sys; 5 open, read, fprint, fildes, tokenize, 6 ORDWR, OREAD, OWRITE: import sys; 7include "draw.m"; 8 draw: Draw; 9 Font: import draw; 10include "bufio.m"; 11 bufio: Bufio; 12 Iobuf: import bufio; 13include "arg.m"; 14 15font: ref Font; 16columns := 65; 17tabwid := 0; 18mintab := 1; 19 20Mc: module{ 21 init: fn(nil: ref Draw->Context, argv: list of string); 22}; 23 24init(ctxt: ref Draw->Context, argv: list of string) 25{ 26 sys = load Sys Sys->PATH; 27 if((bufio = load Bufio Bufio->PATH) == nil) 28 fatal("can't load " + Bufio->PATH); 29 draw = load Draw Draw->PATH; 30 if((arg := load Arg Arg->PATH) == nil) 31 fatal("can't load " + Arg->PATH); 32 33 getwidth(ctxt); 34 arg->init(argv); 35 arg->setusage("mc [-c columns] [file ...]"); 36 while((c:=arg->opt()) != 0) 37 case c { 38 'c' => columns = int arg->earg() * mintab; 39 * => arg->usage(); 40 } 41 argv = arg->argv(); 42 if(len argv == 0) 43 argv = "/fd/0" :: nil; 44 45 a := array[1024] of (string, int); 46 n := 0; 47 maxwidth := 0; 48 for(; argv!=nil; argv=tl argv){ 49 if((bin:=bufio->open(hd argv, OREAD)) == nil){ 50 fprint(fildes(2), "mc: can't open %s: %r\n", hd argv); 51 continue; 52 } 53 while((s:=bin.gets('\n')) != nil){ 54 if(s[len s-1] == '\n') 55 s = s[0:len s-1]; 56 if(n == len a) 57 a = (array[n+1024] of (string, int))[0:] = a; 58 a[n].t0 = s; 59 a[n].t1 = wordsize(s); 60 if(a[n].t1 > maxwidth) 61 maxwidth = a[n].t1; 62 n++; 63 } 64 bin.close(); 65 } 66 outcols(a[:n], maxwidth); 67} 68 69outcols(words: array of (string, int), maxwidth: int) 70{ 71 maxwidth = nexttab(maxwidth+mintab-1); 72 numcols := columns / maxwidth; 73 if(numcols <= 0) 74 numcols = 1; 75 nwords := len words; 76 nlines := (nwords+numcols-1) / numcols; 77 bout := bufio->fopen(fildes(1), OWRITE); 78 for(i := 0; i < nlines; i++){ 79 col := endcol := 0; 80 for(j:=i; j<nwords; j+=nlines){ 81 endcol += maxwidth; 82 bout.puts(words[j].t0); 83 col += words[j].t1; 84 if(j+nlines < nwords){ 85 while(col < endcol){ 86 if(tabwid) 87 bout.putc('\t'); 88 else 89 bout.putc(' '); 90 col = nexttab(col); 91 } 92 } 93 } 94 bout.putc('\n'); 95 } 96 bout.close(); 97} 98 99wordsize(s: string): int 100{ 101 if(font != nil) 102 return font.width(s); 103 return len s; 104} 105 106nexttab(col: int): int 107{ 108 if(tabwid){ 109 col += tabwid; 110 col -= col%tabwid; 111 return col; 112 } 113 return col+1; 114} 115 116getwidth(ctxt: ref Draw->Context) 117{ 118 if(ctxt == nil || draw == nil) 119 return; 120 if((wid := rf("/env/acmewin")) == nil) 121 return; 122 if((fd := open("/chan/" + wid + "/ctl", ORDWR)) == nil) 123 return; 124 buf := array[256] of byte; 125 if((n := read(fd, buf, len buf)) <= 0) 126 return; 127 (nf, f) := tokenize(string buf[:n], " "); 128 if(nf != 8) 129 return; 130 f0 := tl tl tl tl tl f; 131 if((font = Font.open(ctxt.display, hd tl f0)) == nil) 132 return; 133 tabwid = int hd tl tl f0; 134 mintab = font.width("0"); 135 columns = int hd f0; 136} 137 138fatal(s: string) 139{ 140 fprint(fildes(2), "mc: %s: %r\n", s); 141 raise "fail:"+s; 142} 143 144rf(f: string): string 145{ 146 fd := sys->open(f, Sys->OREAD); 147 if(fd == nil) 148 return nil; 149 b := array[Sys->NAMEMAX] of byte; 150 n := sys->read(fd, b, len b); 151 if(n < 0) 152 return nil; 153 return string b[0:n]; 154} 155