dan@rna.UUCP (Dan Ts'o) (01/26/85)
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; }