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 <sys/ioctl.h>
12 #include <sys/termios.h>
13 #include <libc.h>
14 #include <draw.h>
15 #include <bio.h>
17 #define WIDTH 80
18 #define TAB 4
19 #define WORD_ALLOC_QUANTA 1024
20 #define ALLOC_QUANTA 4096
22 int linewidth=WIDTH;
23 int colonflag=0;
24 int tabflag=0; /* -t flag turned off forever */
25 Rune *cbuf, *cbufp;
26 Rune **word;
27 int maxwidth=0;
28 int nalloc=ALLOC_QUANTA;
29 int nwalloc=WORD_ALLOC_QUANTA;
30 int nchars=0;
31 int nwords=0;
32 Biobuf bin;
33 Biobuf bout;
35 void getwidth(void), readbuf(int), error(char *);
36 void scanwords(void), columnate(void), morechars(void);
38 void
39 main(int argc, char *argv[])
40 {
41 int i;
42 int lineset;
43 int ifd;
45 lineset = 0;
46 Binit(&bout, 1, OWRITE);
47 while(argc > 1 && argv[1][0] == '-'){
48 --argc; argv++;
49 switch(argv[0][1]){
50 case '\0':
51 colonflag = 1;
52 break;
53 case 't':
54 tabflag = 0;
55 break;
56 default:
57 linewidth = atoi(&argv[0][1]);
58 if(linewidth <= 1)
59 linewidth = WIDTH;
60 lineset = 1;
61 break;
62 }
63 }
64 if(lineset == 0)
65 getwidth();
66 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
67 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
68 if(word == 0 || cbuf == 0)
69 error("out of memory");
70 if(argc == 1)
71 readbuf(0);
72 else{
73 for(i = 1; i < argc; i++){
74 if((ifd = open(*++argv, OREAD)) == -1)
75 fprint(2, "mc: can't open %s (%r)\n", *argv);
76 else{
77 readbuf(ifd);
78 Bflush(&bin);
79 close(ifd);
80 }
81 }
82 }
83 columnate();
84 exits(0);
85 }
86 void
87 error(char *s)
88 {
89 fprint(2, "mc: %s\n", s);
90 exits(s);
91 }
92 void
93 readbuf(int fd)
94 {
95 int lastwascolon = 0;
96 long c;
97 int linesiz = 0;
99 Binit(&bin, fd, OREAD);
100 do{
101 if(nchars++ >= nalloc)
102 morechars();
103 *cbufp++ = c = Bgetrune(&bin);
104 linesiz++;
105 if(c == '\t') {
106 cbufp[-1] = L' ';
107 while(linesiz%TAB != 0) {
108 if(nchars++ >= nalloc)
109 morechars();
110 *cbufp++ = L' ';
111 linesiz++;
114 if(colonflag && c == ':')
115 lastwascolon++;
116 else if(lastwascolon){
117 if(c == '\n'){
118 --nchars; /* skip newline */
119 *cbufp = L'\0';
120 while(nchars > 0 && cbuf[--nchars] != '\n')
122 if(nchars)
123 nchars++;
124 columnate();
125 if (nchars)
126 Bputc(&bout, '\n');
127 Bprint(&bout, "%S", cbuf+nchars);
128 nchars = 0;
129 cbufp = cbuf;
131 lastwascolon = 0;
133 if(c == '\n')
134 linesiz = 0;
135 }while(c >= 0);
137 void
138 scanwords(void)
140 Rune *p, *q;
141 int i;
143 nwords=0;
144 maxwidth=0;
145 for(p = q = cbuf, i = 0; i < nchars; i++){
146 if(*p++ == L'\n'){
147 if(nwords >= nwalloc){
148 nwalloc += WORD_ALLOC_QUANTA;
149 if((word = realloc(word, nwalloc*sizeof(*word)))==0)
150 error("out of memory");
152 word[nwords++] = q;
153 p[-1] = L'\0';
154 if(p-q > maxwidth)
155 maxwidth = p-q;
156 q = p;
161 void
162 columnate(void)
164 int i, j;
165 int words_per_line;
166 int nlines;
167 int col;
168 int endcol;
171 scanwords();
172 if(nwords==0)
173 return;
174 words_per_line = linewidth/maxwidth;
175 if(words_per_line <= 0)
176 words_per_line = 1;
177 nlines=(nwords+words_per_line-1)/words_per_line;
178 for(i = 0; i < nlines; i++){
179 col = endcol = 0;
180 for(j = i; j < nwords; j += nlines){
181 endcol += maxwidth;
182 Bprint(&bout, "%S", word[j]);
183 col += word[j+1]-word[j]-1;
184 if(j+nlines < nwords){
185 if(tabflag) {
186 int tabcol = (col|(TAB-1))+1;
187 while(tabcol <= endcol){
188 Bputc(&bout, '\t');
189 col = tabcol;
190 tabcol += TAB;
193 while(col < endcol){
194 Bputc(&bout, ' ');
195 col++;
199 Bputc(&bout, '\n');
203 void
204 morechars(void)
206 nalloc += ALLOC_QUANTA;
207 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
208 error("out of memory");
209 cbufp = cbuf+nchars-1;
212 /*
213 * These routines discover the width of the display.
214 * It takes some work. If we do the easy calls to the
215 * draw library, the screen flashes due to repainting
216 * when mc exits.
217 */
219 int
220 windowrect(struct winsize *ws)
222 int tty;
224 if((tty = open("/dev/tty", OWRITE)) < 0)
225 tty = 1;
227 if(ioctl(tty, TIOCGWINSZ, ws) < 0){
228 if(tty != 1)
229 close(tty);
230 return -1;
232 if(tty != 1)
233 close(tty);
234 return 0;
237 void
238 getwidth(void)
240 struct winsize ws;
242 if(windowrect(&ws) < 0)
243 return;
244 linewidth = ws.ws_col;