Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
15
#define	WIDTH			80
16
#define	TAB	4
17
#define	WORD_ALLOC_QUANTA	1024
18
#define	ALLOC_QUANTA		4096
19
 
20
int linewidth=WIDTH;
21
int mintab=1;
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
int tabwidth=0;
32
Font *font;
33
Biobuf	bin;
34
Biobuf	bout;
35
 
36
void getwidth(void), readbuf(int), error(char *);
37
void scanwords(void), columnate(void), morechars(void);
38
int wordwidth(Rune*, int);
39
int nexttab(int);
40
 
41
void
42
main(int argc, char *argv[])
43
{
44
	int i;
45
	int lineset;
46
	int ifd;
47
 
48
	lineset = 0;
49
	Binit(&bout, 1, OWRITE);
50
	while(argc > 1 && argv[1][0] == '-'){
51
		--argc; argv++;
52
		switch(argv[0][1]){
53
		case '\0':
54
			colonflag = 1;
55
			break;
56
		case 't':
57
			tabflag = 0;
58
			break;
59
		default:
60
			linewidth = atoi(&argv[0][1]);
61
			if(linewidth <= 1)
62
				linewidth = WIDTH;
63
			lineset = 1;
64
			break;
65
		}
66
	}
67
	if(lineset == 0){
68
		getwidth();
69
		if(linewidth <= 1){
70
			linewidth = WIDTH;
71
			font = nil;
72
		}
73
	}
74
 
75
	cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
76
	word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
77
	if(word == 0 || cbuf == 0)
78
		error("out of memory");
79
	if(argc == 1)
80
		readbuf(0);
81
	else{
82
		for(i = 1; i < argc; i++){
83
			if((ifd = open(*++argv, OREAD)) == -1)
84
				fprint(2, "mc: can't open %s (%r)\n", *argv);
85
			else{
86
				readbuf(ifd);
87
				Bflush(&bin);
88
				close(ifd);
89
			}
90
		}
91
	}
92
	columnate();
93
	exits(0);
94
}
95
void
96
error(char *s)
97
{
98
	fprint(2, "mc: %s\n", s);
99
	exits(s);
100
}
101
void
102
readbuf(int fd)
103
{
104
	int lastwascolon = 0;
105
	long c;
106
	int linesiz = 0;
107
 
108
	Binit(&bin, fd, OREAD);
109
	do{
110
		if(nchars++ >= nalloc)
111
			morechars();
112
		*cbufp++ = c = Bgetrune(&bin);
113
		linesiz++;
114
		if(c == '\t') {
115
			cbufp[-1] = L' ';
116
			while(linesiz%TAB != 0) {
117
				if(nchars++ >= nalloc)
118
					morechars();
119
				*cbufp++ = L' ';
120
				linesiz++;
121
			}
122
		}
123
		if(colonflag && c == ':')
124
			lastwascolon++;
125
		else if(lastwascolon){
126
			if(c == '\n'){
127
				--nchars; 	/* skip newline */
128
				*cbufp = L'\0';
129
				while(nchars > 0 && cbuf[--nchars] != '\n')
130
					;
131
				if(nchars)
132
					nchars++;
133
				columnate();
134
				if (nchars)
135
					Bputc(&bout, '\n');
136
				Bprint(&bout, "%S", cbuf+nchars);
137
				nchars = 0;
138
				cbufp = cbuf;
139
			}
140
			lastwascolon = 0;
141
		}
142
		if(c == '\n')
143
			linesiz = 0;
144
	}while(c >= 0);
145
}
146
void
147
scanwords(void)
148
{
149
	Rune *p, *q;
150
	int i, w;
151
 
152
	nwords=0;
153
	maxwidth=0;
154
	for(p = q = cbuf, i = 0; i < nchars; i++){
155
		if(*p++ == L'\n'){
156
			if(nwords >= nwalloc){
157
				nwalloc += WORD_ALLOC_QUANTA;
158
				if((word = realloc(word, nwalloc*sizeof(*word)))==0)
159
					error("out of memory");
160
			}
161
			word[nwords++] = q;
162
			p[-1] = L'\0';
163
			w = wordwidth(q, p-q-1);
164
			if(w > maxwidth)
165
				maxwidth = w;
166
			q = p;
167
		}
168
	}
169
}
170
 
171
void
172
columnate(void)
173
{
174
	int i, j;
175
	int words_per_line;
176
	int nlines;
177
	int col;
178
	int endcol;
179
 
180
 
181
	scanwords();
182
	if(nwords==0)
183
		return;
184
	maxwidth = nexttab(maxwidth+mintab-1);
185
	words_per_line = linewidth/maxwidth;
186
	if(words_per_line <= 0)
187
		words_per_line = 1;
188
	nlines=(nwords+words_per_line-1)/words_per_line;
189
	for(i = 0; i < nlines; i++){
190
		col = endcol = 0;
191
		for(j = i; j < nwords; j += nlines){
192
			endcol += maxwidth;
193
			Bprint(&bout, "%S", word[j]);
194
			col += wordwidth(word[j], runestrlen(word[j]));
195
			if(j+nlines < nwords){
196
				if(tabflag) {
197
					while(col < endcol){
198
						Bputc(&bout, '\t');
199
						col = nexttab(col);
200
					}
201
				}else{
202
					while(col < endcol){
203
						Bputc(&bout, ' ');
204
						col++;
205
					}
206
				}
207
			}
208
		}
209
		Bputc(&bout, '\n');
210
	}
211
}
212
 
213
int
214
wordwidth(Rune *w, int nw)
215
{
216
	if(font)
217
		return runestringnwidth(font, w, nw);
218
	return nw;
219
}
220
 
221
int
222
nexttab(int col)
223
{
224
	if(tabwidth){
225
		col += tabwidth;
226
		col -= col%tabwidth;
227
		return col;
228
	}
229
	return col+1;
230
}
231
 
232
void
233
morechars(void)
234
{
235
	nalloc += ALLOC_QUANTA;
236
	if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
237
		error("out of memory");
238
	cbufp = cbuf+nchars-1;
239
}
240
 
241
/*
242
 * These routines discover the width of the display.
243
 * It takes some work.  If we do the easy calls to the
244
 * draw library, the screen flashes due to repainting
245
 * when mc exits.
246
 */
247
 
248
jmp_buf	drawjmp;
249
 
250
void
251
terror(Display*, char*)
252
{
253
	longjmp(drawjmp, 1);
254
}
255
 
256
void
257
getwidth(void)
258
{
259
	int n, fd;
260
	char buf[128], *f[10], *p;
261
 
262
	if(access("/dev/acme", OREAD) >= 0){
263
		if((fd = open("/dev/acme/ctl", OREAD)) < 0)
264
			return;
265
		n = read(fd, buf, sizeof buf-1);
266
		close(fd);
267
		if(n <= 0)
268
			return;
269
		buf[n] = 0;
270
		n = tokenize(buf, f, nelem(f));
271
		if(n < 7)
272
			return;
273
		if((font = openfont(nil, f[6])) == nil)
274
			return;
275
		if(n >= 8)
276
			tabwidth = atoi(f[7]);
277
		else
278
			tabwidth = 4*stringwidth(font, "0");
279
		mintab = stringwidth(font, "0");
280
		linewidth = atoi(f[5]);
281
		tabflag = 1;
282
		return;
283
	}
284
 
285
	if((p = getenv("font")) == nil)
286
		return;
287
	if((font = openfont(nil, p)) == nil)
288
		return;
289
	if((fd = open("/dev/window", OREAD)) < 0){
290
		font = nil;
291
		return;
292
	}
293
	n = read(fd, buf, 5*12);
294
	close(fd);
295
	if(n < 5*12){
296
		font = nil;
297
		return;
298
	}
299
	buf[n] = 0;
300
 
301
	/* window stucture:
302
		4 bit left edge
303
		1 bit gap
304
		12 bit scrollbar
305
		4 bit gap
306
		text
307
		4 bit right edge
308
	*/
309
	linewidth = atoi(buf+3*12) - atoi(buf+1*12) - (4+1+12+4+4);
310
	mintab = stringwidth(font, "0");
311
	if((p = getenv("tabstop")) != nil)
312
		tabwidth = atoi(p)*stringwidth(font, "0");
313
	if(tabwidth == 0)
314
		tabwidth = 4*stringwidth(font, "0");
315
	tabflag = 1;
316
}