326 lines
5.8 KiB
C
326 lines
5.8 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
|
|
/*
|
|
* mc - columnate
|
|
*
|
|
* mc[-][-LINEWIDTH][-t][file...]
|
|
* - causes break on colon
|
|
* -LINEWIDTH sets width of line in which to columnate(default 80)
|
|
* -t suppresses expanding multiple blanks into tabs
|
|
*
|
|
*/
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <draw.h>
|
|
#include <bio.h>
|
|
|
|
#define WIDTH 80
|
|
#define TAB 4
|
|
#define WORD_ALLOC_QUANTA 1024
|
|
#define ALLOC_QUANTA 4096
|
|
|
|
int linewidth=WIDTH;
|
|
int mintab=1;
|
|
int colonflag=0;
|
|
int tabflag=0; /* -t flag turned off forever */
|
|
Rune *cbuf, *cbufp;
|
|
Rune **word;
|
|
int maxwidth=0;
|
|
int nalloc=ALLOC_QUANTA;
|
|
int nwalloc=WORD_ALLOC_QUANTA;
|
|
int nchars=0;
|
|
int nwords=0;
|
|
int tabwidth=0;
|
|
Font *font;
|
|
Biobuf bin;
|
|
Biobuf bout;
|
|
|
|
void getwidth(void), readbuf(int), error(char *);
|
|
void scanwords(void), columnate(void), morechars(void);
|
|
int wordwidth(Rune*, int);
|
|
int nexttab(int);
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i;
|
|
int lineset;
|
|
int ifd;
|
|
|
|
lineset = 0;
|
|
Binit(&bout, 1, OWRITE);
|
|
while(argc > 1 && argv[1][0] == '-'){
|
|
--argc; argv++;
|
|
switch(argv[0][1]){
|
|
case '\0':
|
|
colonflag = 1;
|
|
break;
|
|
case 't':
|
|
tabflag = 0;
|
|
break;
|
|
default:
|
|
linewidth = atoi(&argv[0][1]);
|
|
if(linewidth <= 1)
|
|
linewidth = WIDTH;
|
|
lineset = 1;
|
|
break;
|
|
}
|
|
}
|
|
if(lineset == 0){
|
|
getwidth();
|
|
if(linewidth <= 1){
|
|
linewidth = WIDTH;
|
|
font = nil;
|
|
}
|
|
}
|
|
|
|
cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
|
|
word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
|
|
if(word == 0 || cbuf == 0)
|
|
error("out of memory");
|
|
if(argc == 1)
|
|
readbuf(0);
|
|
else{
|
|
for(i = 1; i < argc; i++){
|
|
if((ifd = open(*++argv, OREAD)) == -1)
|
|
fprint(2, "mc: can't open %s (%r)\n", *argv);
|
|
else{
|
|
readbuf(ifd);
|
|
Bflush(&bin);
|
|
close(ifd);
|
|
}
|
|
}
|
|
}
|
|
columnate();
|
|
exits(0);
|
|
}
|
|
void
|
|
error(char *s)
|
|
{
|
|
fprint(2, "mc: %s\n", s);
|
|
exits(s);
|
|
}
|
|
void
|
|
readbuf(int fd)
|
|
{
|
|
int lastwascolon = 0;
|
|
int32_t c;
|
|
int linesiz = 0;
|
|
|
|
Binit(&bin, fd, OREAD);
|
|
do{
|
|
if(nchars++ >= nalloc)
|
|
morechars();
|
|
*cbufp++ = c = Bgetrune(&bin);
|
|
linesiz++;
|
|
if(c == '\t') {
|
|
cbufp[-1] = L' ';
|
|
while(linesiz%TAB != 0) {
|
|
if(nchars++ >= nalloc)
|
|
morechars();
|
|
*cbufp++ = L' ';
|
|
linesiz++;
|
|
}
|
|
}
|
|
if(colonflag && c == ':')
|
|
lastwascolon++;
|
|
else if(lastwascolon){
|
|
if(c == '\n'){
|
|
--nchars; /* skip newline */
|
|
*cbufp = L'\0';
|
|
while(nchars > 0 && cbuf[--nchars] != '\n')
|
|
;
|
|
if(nchars)
|
|
nchars++;
|
|
columnate();
|
|
if (nchars)
|
|
Bputc(&bout, '\n');
|
|
Bprint(&bout, "%S", cbuf+nchars);
|
|
nchars = 0;
|
|
cbufp = cbuf;
|
|
}
|
|
lastwascolon = 0;
|
|
}
|
|
if(c == '\n')
|
|
linesiz = 0;
|
|
}while(c >= 0);
|
|
}
|
|
void
|
|
scanwords(void)
|
|
{
|
|
Rune *p, *q;
|
|
int i, w;
|
|
|
|
nwords=0;
|
|
maxwidth=0;
|
|
for(p = q = cbuf, i = 0; i < nchars; i++){
|
|
if(*p++ == L'\n'){
|
|
if(nwords >= nwalloc){
|
|
nwalloc += WORD_ALLOC_QUANTA;
|
|
if((word = realloc(word, nwalloc*sizeof(*word)))==0)
|
|
error("out of memory");
|
|
}
|
|
word[nwords++] = q;
|
|
p[-1] = L'\0';
|
|
w = wordwidth(q, p-q-1);
|
|
if(w > maxwidth)
|
|
maxwidth = w;
|
|
q = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
columnate(void)
|
|
{
|
|
int i, j;
|
|
int words_per_line;
|
|
int nlines;
|
|
int col;
|
|
int endcol;
|
|
|
|
|
|
scanwords();
|
|
if(nwords==0)
|
|
return;
|
|
maxwidth = nexttab(maxwidth+mintab-1);
|
|
words_per_line = linewidth/maxwidth;
|
|
if(words_per_line <= 0)
|
|
words_per_line = 1;
|
|
nlines=(nwords+words_per_line-1)/words_per_line;
|
|
for(i = 0; i < nlines; i++){
|
|
col = endcol = 0;
|
|
for(j = i; j < nwords; j += nlines){
|
|
endcol += maxwidth;
|
|
Bprint(&bout, "%S", word[j]);
|
|
col += wordwidth(word[j], runestrlen(word[j]));
|
|
if(j+nlines < nwords){
|
|
if(tabflag) {
|
|
while(col < endcol){
|
|
Bputc(&bout, '\t');
|
|
col = nexttab(col);
|
|
}
|
|
}else{
|
|
while(col < endcol){
|
|
Bputc(&bout, ' ');
|
|
col++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Bputc(&bout, '\n');
|
|
}
|
|
}
|
|
|
|
int
|
|
wordwidth(Rune *w, int nw)
|
|
{
|
|
if(font)
|
|
return runestringnwidth(font, w, nw);
|
|
return nw;
|
|
}
|
|
|
|
int
|
|
nexttab(int col)
|
|
{
|
|
if(tabwidth){
|
|
col += tabwidth;
|
|
col -= col%tabwidth;
|
|
return col;
|
|
}
|
|
return col+1;
|
|
}
|
|
|
|
void
|
|
morechars(void)
|
|
{
|
|
nalloc += ALLOC_QUANTA;
|
|
if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
|
|
error("out of memory");
|
|
cbufp = cbuf+nchars-1;
|
|
}
|
|
|
|
/*
|
|
* These routines discover the width of the display.
|
|
* It takes some work. If we do the easy calls to the
|
|
* draw library, the screen flashes due to repainting
|
|
* when mc exits.
|
|
*/
|
|
|
|
jmp_buf drawjmp;
|
|
|
|
void
|
|
terror(Display *d, char *c)
|
|
{
|
|
longjmp(drawjmp, 1);
|
|
}
|
|
|
|
void
|
|
getwidth(void)
|
|
{
|
|
int n, fd;
|
|
char buf[128], *f[10], *p;
|
|
|
|
if(access("/dev/acme", OREAD) >= 0){
|
|
if((fd = open("/dev/acme/ctl", OREAD)) < 0)
|
|
return;
|
|
n = read(fd, buf, sizeof buf-1);
|
|
close(fd);
|
|
if(n <= 0)
|
|
return;
|
|
buf[n] = 0;
|
|
n = tokenize(buf, f, nelem(f));
|
|
if(n < 7)
|
|
return;
|
|
if((font = openfont(nil, f[6])) == nil)
|
|
return;
|
|
if(n >= 8)
|
|
tabwidth = atoi(f[7]);
|
|
else
|
|
tabwidth = 4*stringwidth(font, "0");
|
|
mintab = stringwidth(font, "0");
|
|
linewidth = atoi(f[5]);
|
|
tabflag = 1;
|
|
return;
|
|
}
|
|
|
|
if((p = getenv("font")) == nil)
|
|
return;
|
|
if((font = openfont(nil, p)) == nil)
|
|
return;
|
|
if((fd = open("/dev/window", OREAD)) < 0){
|
|
font = nil;
|
|
return;
|
|
}
|
|
n = read(fd, buf, 5*12);
|
|
close(fd);
|
|
if(n < 5*12){
|
|
font = nil;
|
|
return;
|
|
}
|
|
buf[n] = 0;
|
|
|
|
/* window stucture:
|
|
4 bit left edge
|
|
1 bit gap
|
|
12 bit scrollbar
|
|
4 bit gap
|
|
text
|
|
4 bit right edge
|
|
*/
|
|
linewidth = atoi(buf+3*12) - atoi(buf+1*12) - (4+1+12+4+4);
|
|
mintab = stringwidth(font, "0");
|
|
if((p = getenv("tabstop")) != nil)
|
|
tabwidth = atoi(p)*stringwidth(font, "0");
|
|
if(tabwidth == 0)
|
|
tabwidth = 4*stringwidth(font, "0");
|
|
tabflag = 1;
|
|
}
|