Multiple column filter
Dan Ts'o
dan at rna.UUCP
Sat Jan 26 11:59:08 AEST 1985
x
Here is a filter "mc" which rearranges input lines to multicolumned
output. That is,
ls | mc
is like
ls -C (On Berkeley systems)
There are other ways of producing multicolumned output, of course.
Two string to mind:
1)
ls | pr -t -4 -l1
2)
ls | paste - - - -
However, neither of these filters duplicates the "ls -C" output,
where the columns proceed downward first, then on to the next column, which
is what "mc" does.
The original code came from the old Harvard UNIX V6 systems, but I
had to modify it a bit to move out of the V6 PDP-11 world.
To compile it,
cc -O mc.c -ltermlib
although, if you don't have libtermlib.a, commenting out three lines
would do fine. In addition,
mc -132
specifies a 132-column output. Normally, columns is taken from TERMCAP.
I find mc useful for all sorts of general purpose re-formatting, like
directory listing of other OS's and long columns of numbers.
Cheers,
Dan Ts'o
Dept. Neurobiology
Rockefeller Univ.
1230 York Ave.
NY, NY 10021
212-570-7671
...cmcl2!rna!dan
/*
* mc - Multiple column filter
* Transform lines of input into listing of multiple columns
* Original code from Harvard V6 Unix
* Updated and reworked by Dan Ts'o, Rockefeller Univ.
* Now has cat-like syntax:
* mc [-] [file ...]
*/
#include <stdio.h>
#define MEMINCR 1024L /* Memory buffer increments */
#define ZSTACK1 (-1) /* An impossible (char *) (Sorry) */
char *nodename;
int width;
char *malloc(), **stack1();
char *getenv();
main(c,v)
char **v;
{
register int i,f;
register char *cp;
FILE *fd;
char tbuf[1024];
/* Uncomment if your stdio doesn't buffer stdout
char buf[BUFSIZ];
setbuf(stdout, buf);
*/
f = 0;
nodename = *v;
cp = getenv("TERM");
if (cp == NULL || tgetent(tbuf, cp) <= 0
|| (width = tgetnum("co")-1) < 8)
width = 79;
while (c > 1 && v[1][0] == '-') {
c--;
v++;
switch (v[0][1]) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width = atoi(&v[0][1]);
break;
default:
error("%s: Bad option\n", *v);
}
}
if (--c == 0)
exit(xfer(stdin));
else {
while (c--) {
v++;
if (**v == '-' && v[0][1] == 0) {
xfer(stdin);
clearerr(stdin);
}
else {
if ((fd = fopen(*v, "r")) == NULL) {
fprintf(stderr, "%s: %s: Can't open\n",
nodename, *v);
f++;
}
else {
xfer(fd);
fclose(fd);
}
}
}
}
exit(f ? -1 : 0);
}
xfer(fin)
FILE *fin;
{
register int i;
register char *cp;
char line[1024];
int max, items, columns;
int row_p, index, rows, col_p;
char **bot;
items = max = 0;
while(fgets(line, sizeof line, fin) != NULL) {
i = strlen(line);
if (line[--i] == '\n')
line[i] = 0;
else
i++;
if(i >= width) {
error("Line of length=%d is too long for width=%d\n",
i, width);
}
if((cp = (char *)malloc(i+1)) == NULL)
error("Out of memory\n");
strcpy(cp, line);
bot = stack1(cp);
if(i > max) max = i;
items++;
}
columns = width / (max+1);
rows = (items + columns - 1) / columns;
for(row_p = 0; row_p < rows; row_p++) {
for(col_p = 0; col_p < columns; col_p++) {
index = (col_p * rows) + row_p;
if(index >= items)
continue;
if((col_p + 1) * rows + row_p >= items)
printf("%s", bot[items - index - 1]);
else
printf("%-*s ", max, bot[items - index - 1]);
}
printf("\n");
}
fflush(stdout);
stack1(ZSTACK1);
return ferror(fin);
}
error(a, b, c, d, e)
{
fprintf(stderr, "%s: ", nodename);
fprintf(stderr, a, b, c, d, e);
exit (1);
}
char **stack1(s)
char *s;
{
static char **s_beg, **s_end;
static long nbuf = 0;
register char **v, **u;
register long n;
if (s == (char *) ZSTACK1) {
if (nbuf > 0)
free(s_beg);
nbuf = 0;
return 0;
}
if (nbuf == 0 || s_end <= s_beg) {
n = MEMINCR * (nbuf+1);
v = (char **)malloc(n*(sizeof (char *)));
if (v == NULL)
error("mc: Out of memory\n");
s_beg = v;
v += n;
if (nbuf > 0) {
u = s_end+(MEMINCR*nbuf);
while (u > s_end)
*--v = *--u;
free(s_end);
}
nbuf++;
s_end = v;
}
*--s_end = s;
return s_end;
}
More information about the Comp.sources.unix
mailing list