#!/usr/local/bin/clisp -ansi -q -E utf-8
;;;; -*- mode:lisp; coding:utf-8 -*-
;;;;FILE:               columnify
;;;;LANGUAGE:           text
;;;;SYSTEM:             POSIX
;;;;    Columnify the input.
;;;;    By default, columnify as much as possible given the line lengths
;;;;    and the terminal width as given by the environment variable COLUMNS.
;;;;    <PJB> Pascal Bourguignon <pjb@informatimago.com>
;;;;    2007-04-19 <PJB>
;;;;    GPL
;;;;    Copyright Pascal Bourguignon 2007 - 2007
;;;;    This program is free software; you can redistribute it and/or
;;;;    modify it under the terms of the GNU General Public License
;;;;    as published by the Free Software Foundation; either version
;;;;    2 of the License, or (at your option) any later version.
;;;;    This program is distributed in the hope that it will be
;;;;    useful, but WITHOUT ANY WARRANTY; without even the implied
;;;;    PURPOSE.  See the GNU General Public License for more details.
;;;;    You should have received a copy of the GNU General Public
;;;;    License along with this program; if not, write to the Free
;;;;    Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;;    Boston, MA 02111-1307 USA

(defvar *width* (or (nth-value 1 (screen:with-window (screen:window-size screen:*window*)))
                    (and (ext:getenv "COLUMNS") (parse-integer (ext:getenv "COLUMNS")))
                    (block :found
                      (dolist (path (list (format nil "/proc/~D/fd/1" (posix:process-id))
                                          "/dev/tty") nil)
                        (with-open-stream (stty (ext:run-shell-command (format nil "bash -c 'stty -a < ~S' 2>/dev/null" path)
                                                                       :input :terminal
                                                                       :output :stream))
                            :for line = (read-line stty nil nil)
                            :while line
                            :do (let* ((tag " columns ")
                                       (pos (search tag line)))
                                  (when pos
                                    (return-from :found
                                      (parse-integer line :start (+ pos (length tag))
                                                     :junk-allowed t))))))))

(defun columnify (lines width)
  (let* ((colwid (1+ (or (loop :for line :in lines :maximize (length line)) 0)))
         (ncols  (truncate width colwid)))
    (if (<= ncols 1)
        (loop :for line :in lines :do (princ line) (terpri))
        ;; columnify:
        (let* ((nrows     (ceiling (length lines) ncols))
               (cols      (make-array (list ncols nrows) :initial-element ""))
               (longcols  (mod (length lines) ncols))
               (next-line lines))
            :for col :from 0 :below ncols
            :do (loop
                  :for row :from 0 :below (- nrows (if (< col longcols) 0 1))
                  :do (setf (aref cols col row) (pop next-line))))
          (loop :for row :from 0 :below nrows
            :do (loop
                  :for col :from 0 :below ncols
                  :do (format t "~VA" colwid (aref cols col row))
                  :finally (format t "~%")))))))

(defun main ()
  (columnify (loop
               :for line = (read-line *standard-input* nil nil)
               :while line :collect line)

(when (BOUNDP 'EXT:*ARGS*)
  (ext:exit 0))