#! /usr/bin/gawk -f # Last edited on 2008-06-15 07:27:55 by stolfi BEGIN { USAGE = ( \ "multicol \\\n" \ " [ -v titles=\"T1 T2 ... Tn\" ] \\\n" \ " [ -v clean={BOOL} ] \\\n" \ " [ -v colsep=STRING ] \\\n" \ " FILE..." \ ); # Reads abort = -1; # error indicator # Default values: if ( colsep == "" ) { colsep = " "; } if ( clean == "" ) { clean = 0; } else { clean += 0; } # Table data: split("", width); # {width[i]} is the max line width of file {ARGV[i]}. split("", height); # {height[i]} is the number of lines of file {ARGV[i]}. maxlines = 0; # Max number of lines among all files. # Scan files {ARGV[1..ARGC-1]} and save their widths and heights: for (i = 1; i < ARGC; i++) { get_filedims(ARGV[i]); width[i] = maxwidth; height[i] = numlines; if (numlines > maxlines) { maxlines = numlines; } # printf "%s wd = %d ht = %d\n", ARGV[i], width[i], height[i] > "/dev/stderr"; } # Print headers, if given: if (titles != "") { # decompose `titles' into separate fields `hd[1..nh]': nh = split(titles, hd); if (nh != ARGC-1) { error("bad titles"); } # print column titles for (i = 1; i < ARGC; i++) { if (i > 1) { printf "%s", colsep; } if (length(hd[i]) > width[i]) { width[i] = length(hd[i]); } printf "%-*s", width[i], hd[i]; } printf "\n"; # print dashes for (i = 1; i < ARGC; i++) { if (i > 1) { printf "%s", colsep; } for (r = 1; r <= width[i]; r++) { printf "-"; } } printf "\n"; } # Print the file records: for (k = 1; k <= maxlines; k++) { for (i = 1; i < ARGC; i++) { if (k > height[i]) { line = ""; } else { get_next_line(ARGV[i]); } if (i > 1) { printf "%s", colsep; } printf "%-*s", width[i], line; } printf "\n"; } ARGC = 1; abort = 0; exit(0); } (abort >= 0) { exit abort; } /./ { error("input ignored"); } END { if (abort >= 0) { exit abort; } } function error(msg) { printf "%s\n", msg > "/dev/stderr"; abort = 1; exit 1; } function get_filedims(name, line,len) { # Scans file "{name}", sets {maxwidth} to the the maximum line length, # and sets {numlines} to the number of lines. # Honors the {clean} parameter. maxwidth = 0; numlines = 0; while (get_next_line(name) > 0) { numlines++; len = length(line); if (len > maxwidth) { maxwidth = len; } } if (ERRNO != "0") { error((name ": " ERRNO)); } close(name); } function get_next_line(name) { # Reads the next line from file "{name}" into the global variable {line}. # Returns 1 if success, 0 on EOF. # If {clean} is TRUE, strips '#'-comments, strips leading and # trailing blanks, normalizes internal blanks to 1 blank, and skips # empty lines. if (clean) { do { # Read a line and clean it: if (! (getline line < name)) { return 0; } # Eliminate funny whitespace: gsub(/[\011]/, " ", line); gsub(/[\014\015]/, "", line); # Strip '#'-comments: gsub(/[\#].*$/, "", line); # Regularize spaces: gsub(/[ ]+$/, "", line); gsub(/^[ ]/, "", line); gsub(/[ ][ ]+/, " ", line); } while(line == ""); return 1; } else { # Read a line, as is: return (getline line < name); } }