Blob


1 /*
2 * mc - columnate
3 *
4 * mc[-][-LINEWIDTH][-t][file...]
5 * - causes break on colon
6 * -LINEWIDTH sets width of line in which to columnate(default 80)
7 * -t suppresses expanding multiple blanks into tabs
8 *
9 */
10 #include <u.h>
11 #include <libc.h>
12 #include <draw.h>
13 #include <bio.h>
14 #include <sys/ioctl.h>
16 #define WIDTH 80
17 #define TAB 4
18 #define WORD_ALLOC_QUANTA 1024
19 #define ALLOC_QUANTA 4096
21 int linewidth=WIDTH;
22 int colonflag=0;
23 int tabflag=0; /* -t flag turned off forever */
24 Rune *cbuf, *cbufp;
25 Rune **word;
26 int maxwidth=0;
27 int nalloc=ALLOC_QUANTA;
28 int nwalloc=WORD_ALLOC_QUANTA;
29 int nchars=0;
30 int nwords=0;
31 Biobuf bin;
32 Biobuf bout;
34 void getwidth(void), readbuf(int), error(char *);
35 void scanwords(void), columnate(void), morechars(void);
37 void
38 main(int argc, char *argv[])
39 {
40 int i;
41 int lineset;
42 int ifd;
44 lineset = 0;
45 Binit(&bout, 1, OWRITE);
46 while(argc > 1 && argv[1][0] == '-'){
47 --argc; argv++;
48 switch(argv[0][1]){
49 case '\0':
50 colonflag = 1;
51 break;
52 case 't':
53 tabflag = 0;
54 break;
55 default:
56 linewidth = atoi(&argv[0][1]);
57 if(linewidth <= 1)
58 linewidth = WIDTH;
59 lineset = 1;
60 break;
61 }
62 }
63 if(lineset == 0)
64 getwidth();
65 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
66 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
67 if(word == 0 || cbuf == 0)
68 error("out of memory");
69 if(argc == 1)
70 readbuf(0);
71 else{
72 for(i = 1; i < argc; i++){
73 if((ifd = open(*++argv, OREAD)) == -1)
74 fprint(2, "mc: can't open %s (%r)\n", *argv);
75 else{
76 readbuf(ifd);
77 Bflush(&bin);
78 close(ifd);
79 }
80 }
81 }
82 columnate();
83 exits(0);
84 }
85 void
86 error(char *s)
87 {
88 fprint(2, "mc: %s\n", s);
89 exits(s);
90 }
91 void
92 readbuf(int fd)
93 {
94 int lastwascolon = 0;
95 long c;
96 int linesiz = 0;
98 Binit(&bin, fd, OREAD);
99 do{
100 if(nchars++ >= nalloc)
101 morechars();
102 *cbufp++ = c = Bgetrune(&bin);
103 linesiz++;
104 if(c == '\t') {
105 cbufp[-1] = L' ';
106 while(linesiz%TAB != 0) {
107 if(nchars++ >= nalloc)
108 morechars();
109 *cbufp++ = L' ';
110 linesiz++;
113 if(colonflag && c == ':')
114 lastwascolon++;
115 else if(lastwascolon){
116 if(c == '\n'){
117 --nchars; /* skip newline */
118 *cbufp = L'\0';
119 while(nchars > 0 && cbuf[--nchars] != '\n')
121 if(nchars)
122 nchars++;
123 columnate();
124 if (nchars)
125 Bputc(&bout, '\n');
126 Bprint(&bout, "%S", cbuf+nchars);
127 nchars = 0;
128 cbufp = cbuf;
130 lastwascolon = 0;
132 if(c == '\n')
133 linesiz = 0;
134 }while(c >= 0);
136 void
137 scanwords(void)
139 Rune *p, *q;
140 int i;
142 nwords=0;
143 maxwidth=0;
144 for(p = q = cbuf, i = 0; i < nchars; i++){
145 if(*p++ == L'\n'){
146 if(nwords >= nwalloc){
147 nwalloc += WORD_ALLOC_QUANTA;
148 if((word = realloc(word, nwalloc*sizeof(*word)))==0)
149 error("out of memory");
151 word[nwords++] = q;
152 p[-1] = L'\0';
153 if(p-q > maxwidth)
154 maxwidth = p-q;
155 q = p;
160 void
161 columnate(void)
163 int i, j;
164 int words_per_line;
165 int nlines;
166 int col;
167 int endcol;
170 scanwords();
171 if(nwords==0)
172 return;
173 words_per_line = linewidth/maxwidth;
174 if(words_per_line <= 0)
175 words_per_line = 1;
176 nlines=(nwords+words_per_line-1)/words_per_line;
177 for(i = 0; i < nlines; i++){
178 col = endcol = 0;
179 for(j = i; j < nwords; j += nlines){
180 endcol += maxwidth;
181 Bprint(&bout, "%S", word[j]);
182 col += word[j+1]-word[j]-1;
183 if(j+nlines < nwords){
184 if(tabflag) {
185 int tabcol = (col|(TAB-1))+1;
186 while(tabcol <= endcol){
187 Bputc(&bout, '\t');
188 col = tabcol;
189 tabcol += TAB;
192 while(col < endcol){
193 Bputc(&bout, ' ');
194 col++;
198 Bputc(&bout, '\n');
202 void
203 morechars(void)
205 nalloc += ALLOC_QUANTA;
206 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
207 error("out of memory");
208 cbufp = cbuf+nchars-1;
211 /*
212 * These routines discover the width of the display.
213 * It takes some work. If we do the easy calls to the
214 * draw library, the screen flashes due to repainting
215 * when mc exits.
216 */
218 int
219 windowrect(struct winsize *ws)
221 int tty;
223 if((tty = open("/dev/tty", OWRITE)) < 0)
224 tty = 1;
226 if(ioctl(tty, TIOCGWINSZ, ws) < 0){
227 if(tty != 1)
228 close(tty);
229 return -1;
231 if(tty != 1)
232 close(tty);
233 return 0;
236 void
237 getwidth(void)
239 struct winsize ws;
241 if(windowrect(&ws) < 0)
242 return;
243 linewidth = ws.ws_col;