[comp.sources.unix] v16i087: A columnation program

rsalz@uunet.uu.net (Rich Salz) (11/18/88)

Submitted-by: Gary Oberbrunner <masscomp!garyo>
Posting-number: Volume 16, Issue 87
Archive-name: colm

I got sick of the fact that ls(1) will sort its columns down when given
no arguments, but not in any other case.  And I figured the world needed
a decent columnation tool.  So here is one I just whipped up; it does
fixed and variable width columns, selectable gutter widths, it automatically
figures out how many columns to use (unlike pr -#), and it allows various
formatting options such as selectable leader character, selectable tabbing
with selectable tab size, and your choice of leaders or a separation string.
Colm should compile on any machine that has getopt(3C).
The hooks are in there for multi-page columnation, but it's not done yet.
Any volunteers?

A man page is included.  To make, unpack the shar and type 'make'.  Enjoy!

----------------------------------------------------------------------------
Remember,			Truth is not beauty;      (617)692-6200x2445
Information is not knowledge;	Beauty is not love;	  Gary   Oberbrunner
Knowledge is not wisdom;	Love is not music;	  ...!masscomp!garyo
Wisdom is not truth;		Music is the best. - FZ   ....garyo@masscomp

#--------------------------------- cut here ----------------------------------
# To unpack, cut out all lines above the dotted line, and any lines
# after the similar line near the end of the file.
# Then run the remaining file with /bin/sh (NOT /bin/csh) in the
# appropriate directory.  It will create the following files:
#
#    colm.1
#    makefile
#    colm.h
#    std.h
#    colm.c
#    column.c
#    lists.c
#    output.c
#    readin.c
#    vcolumn.c
#########################################################
if (test -d colm.1) then
  echo colm.1 is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f colm.1) then
  echo 'Should I overwrite the existing version of colm.1 (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f colm.1) then
  echo Overwriting colm.1...
  else
  echo Creating colm.1...
fi
sed 's/-//;s/%$//' << 'END.colm.1' > colm.1
-.\"@(#)colm.1	1.1 6/3/88 22:48:54%
-.RL "MASSCOMP"%
-.TH LS 1%
-.UC%
-.SH NAME%
-colm \- columnate lines of text%
-.SH SYNOPSIS%
-.B colm%
-[%
-.B  -cglnstvwLT%
-] name ...%
-.SH DESCRIPTION%
-.I colm%
-produces multi-column output from single-column input.%
-It is sort of a cross between%
-.I pr%
--<n> (which prints multi-column output sorted across)%
-and the column-sorting function%
-of%
-.I ls%
-(1) (which sorts down, but only if given no filename arguments).%
-It can produce fixed or variable width columns, and it figures out any%
-options not explicitly specified.%
-.PP%
-.I colm%
-uses getopt(3C) to parse its options, so options may be strung%
-together, as in%
-.IR -vw ,%
-and values may either adhere to their option letters or follow as%
-the next argument.%
-The options are as follows:%
-.TP%
-.B \-v%
-Produce variable-width columns.%
-.I colm%
-uses an iterative algorithm to find the maximum number of columns that%
-allows at least the gutter-width between the widest element and the next%
-column.%
-The -v option is incompatible with -c.%
-.TP%
-.BI \-c n%
-Use fixed-width columns of width%
-.IR n .%
-Data will be truncated if necessary to fit the specified column width.%
-If%
-.B -c%
-is not used,%
-.I colm%
-expands the column width(s) to fit the output width.%
-.TP%
-.BI \-g n%
-Use a "gutter" of%
-.I n%
-characters between columns.%
-The default is 1.%
-.TP%
-.BI \-n n%
-Use%
-.I n%
-fixed-width columns.%
-Without%
-.BR -n ,%
-.I colm%
-fits as many columns in the given output width as it can.%
-.TP%
-.B -s%
-Spread the columns to fit the output width.%
-Otherwise columns are made as narrow as possible,%
-while leaving the gutter space between columns.%
-With fixed-width columns, the columns will be spread as far as%
-possible while keeping their widths even.%
-WIth variable-width columns, the columns will be spread so that there%
-is an even amount of white space between them.%
-.TP%
-.BI \-w n%
-Sets the output width to%
-.I n%
-characters.%
-The output lines may be shorter, but cannot be longer than%
-.IR n .%
-.TP%
-.BI \-l n%
-Sets the page length to%
-.I n%
-lines.%
-This option is not implemented.%
-An error message will result if you try to use it.%
-.TP%
-.BI \-L c%
-Sets the%
-.I leader character%
-to%
-.IR c .%
-This character is used repeatedly to fill in the space between columns.%
-The default is to use as many spaces and tabs as are needed.%
--L ' ' will cause%
-.I colm%
-not to use tabs.%
-Watch out for shell metacharacters.%
-.TP%
-.BI \-t s%
-Use the literal string "s" to separate the columns,%
-rather than a repeated leader character.%
-Watch out for shell metacharacters.%
-.br%
-There are two main differences between -L and -t:%
--L only allows a single character, while -t allows a string;%
-and the leader character specified by -L is repeated to fill the%
-space, whereas the string specified with -t is used only once between%
-columns.%
-Generally, -t will not produce even columns, while -L always will.%
-.TP%
-.BI \-T n%
-Specifies the output tab width as%
-.I n%
-characters.%
-The default is eight.%
-.SH DIAGNOSTICS%
-Several errors and warnings can be produced by%
-.IR colm :%
-.br%
-A usage message is produced for illegal options.%
-.br%
-If any single input line is longer than the output width,%
-.I colm%
-terminates with an error.%
-.br%
-Illegal combinations of arguments and impossible conditions,%
-such as 20 columns of 30 characters%
-in an output width of 79 columns, or selecting spreading with a fixed%
-separator string, cause errors.%
-.br%
-Certain combinations of total number of lines and specified number of%
-columns cannot produce balanced columns, even with the last column%
-allowed to be short.%
-If this occurs,%
-.I colm%
-prints an explanatory message on stderr and uses a smaller number%
-of columns than were specified.%
-.br%
-Attempting to do multi-page columnation (with -l) produces an error.%
-.br%
-Nonexistent or unreadable files produce an error.%
-.SH SEE ALSO%
-pr(1), ls(1)%
-.SH BUGS%
-Multi-page columnation is not implemented.%
-.XX "Text manipulation"%
-.XX "Columns, creating"%
END.colm.1
if (test -d makefile) then
  echo makefile is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f makefile) then
  echo 'Should I overwrite the existing version of makefile (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f makefile) then
  echo Overwriting makefile...
  else
  echo Creating makefile...
fi
sed 's/-//;s/%$//' << 'END.makefile' > makefile
-#%
-# Makefile for colm - auto-columnation filter%
-# 5-31-88%
-#%
-SCCSID="@(#)makefile	1.1 6/3/8822:49:03"%
-CFLAGS=-g -I/usr/garyo/lib%
-LIBS=%
-LDFLAGS=-g%
-OBJECTS = colm.o lists.o column.o vcolumn.o readin.o output.o%
-%
-colm: $(OBJECTS)%
-	cc $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)%
-%
-$(OBJECTS): colm.h%
END.makefile
if (test -d colm.h) then
  echo colm.h is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f colm.h) then
  echo 'Should I overwrite the existing version of colm.h (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f colm.h) then
  echo Overwriting colm.h...
  else
  echo Creating colm.h...
fi
sed 's/-//;s/%$//' << 'END.colm.h' > colm.h
-/*----------------------------------------------------------------------%
- * Header file for auto-columnator%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- * SCCS ID: @(#)colm.h	1.1 6/3/88 22:47:12%
- *----------------------------------------------------------------------%
- */%
-%
-#define MAX_COLS 1000		/* maximum number of columns */%
-%
-#define TRUE 1%
-#define FALSE 0%
-%
-typedef int BOOLEAN;%
-%
-/* A doubly-linked list of text lines */%
-typedef struct NODE {%
-    struct NODE *next;%
-    struct NODE *prev;%
-    int length;%
-    char *string;%
-} NODE;%
-%
-extern NODE *findn();%
-%
-extern NODE Lines;		/* the head of the list */%
-				/* defined in lists.c */%
-%
-extern int TotalLines;		/* total # of lines read */%
-				/* defined in readin.c */%
-%
-/* Command-line options: */%
-typedef struct OPTS {%
-    int Vflg;			/* variable col width */%
-    int Sflg;			/* stretch output columns to fit */%
-    int Gutter;			/* blank space between columns */%
-    int ColWidth;		/* fixed col width */%
-    int Ncols;			/* number of cols */%
-    int Width;			/* output width */%
-    int PageLen;		/* page length */%
-    int Tabsize;		/* tab size (normally 8) */%
-    char ColSep[100];		/* separator string */%
-    char Leader;		/* leader char for column separation */%
-} OPTS;%
-%
-extern OPTS Opts;		/* defined in colm.c */%
END.colm.h
if (test -d std.h) then
  echo std.h is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f std.h) then
  echo 'Should I overwrite the existing version of std.h (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f std.h) then
  echo Overwriting std.h...
  else
  echo Creating std.h...
fi
sed 's/-//;s/%$//' << 'END.std.h' > std.h
-/* Standard include file with lots of generally useful stuff */%
-/* Copyright c. 1988, Gary Oberbrunner. */%
-/* This program may be freely redistributed providing that this source code */%
-/* and the accompanying copyright notice are preserved intact. */%
-/* SCCS Id: @(#)std.h	1.2 1/21/88 19:03:14 */%
-%
-#define STDIN 0%
-#define STDOUT 1%
-#define STDERR 2%
-%
-#define min(x,y) ((x) < (y) ? (x) : (y))%
-#define max(x,y) ((x) > (y) ? (x) : (y))%
-#define clamp(x, mn, mx) (((x) <= (mn)) ? (mn) : (((x) >= (mx)) ? (mx) : (x)))%
-%
-#define SECURITY%
-#ifdef SECURITY%
-#define ASSERT(exp) { if (!(exp)) { fprintf(stderr,\%
-	"Assertion error: %s, line %d. Assertion exp failed.\n",\%
-	__FILE__, __LINE__);\%
-	exit(69); } }%
-#else%
-#define ASSERT(exp)%
-#endif%
-%
-#define dbug0(str) \%
-    if (debug) fprintf(stderr, str);%
-#define dbug1(str, arg1) \%
-    if (debug) fprintf(stderr, str, arg1);%
-#define dbug2(str, arg1, arg2) \%
-    if (debug) fprintf(stderr, str, arg1, arg2);%
-#define dbug3(str, arg1, arg2, arg3) \%
-    if (debug) fprintf(stderr, str, arg1, arg2, arg3);%
-#define dbug4(str, arg1, arg2, arg3, arg4) \%
-    if (debug) fprintf(stderr, str, arg1, arg2, arg3, arg4);%
-%
-extern char *malloc();%
-/*%
- * NEW is a macro to malloc 'n' new variables of type 'type'.%
- */%
-#define NEW(var, type, num) \%
-    if ((var = (type *) malloc((num) * sizeof(type)))==NULL) \%
-	{	fprintf(stderr,\%
-	    "ERROR: Out of memory.\nLast request:\n");\%
-	fprintf(stderr,\%
-	    "\tNumber: num\n\tType  : type\n\tName  : var.\n");\%
-	fprintf(stderr,"File %s, line %d\n", __FILE__, __LINE__);\%
-	fprintf(stderr,\%
-	"\tTotal requested: num=%d x sizeof(type)=%d\n\t =%d bytes.\n",\%
-	    num, sizeof(type), (num) * sizeof(type));\%
-	exit(99); }%
END.std.h
if (test -d colm.c) then
  echo colm.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f colm.c) then
  echo 'Should I overwrite the existing version of colm.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f colm.c) then
  echo Overwriting colm.c...
  else
  echo Creating colm.c...
fi
sed 's/-//;s/%$//' << 'END.colm.c' > colm.c
-/*----------------------------------------------------------------------%
- * colm: auto-columnate, with various options.%
- * by Gary Oberbrunner  5-31-88%
- *%
- * -v		variable-width columns (default: fixed-width)%
- * -s		spread output columns to fit output width (default: don't)%
- * -g #		Separate columns by a #-column gutter%
- * -c #		column width (size) (default: max line length of input)%
- * -n #		use # columns (default: program picks max # that will fit)%
- * -w #		output width is # characters/line (default: 80)%
- * -l #		page length is # lines (default: infinite)%
- * -L c		leader character is 'c' (default: space)%
- * -t s		use string "s" as separator; (default: enough space to line up)%
- * -T #		tab size # chars (default 8)%
- *%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include <stdio.h>%
-#include "std.h"%
-#include "colm.h"%
-%
-int debug = 1;%
-static char SCCSId[] = "@(#)colm.c	1.2 6/3/88 (MASSCOMP) 23:17:12";%
-static char Copyright[] = "Copyright c. 1988, Gary Oberbrunner.";%
-%
-OPTS Opts;			/* global copy of original options */%
-main (argc, argv)%
-int argc;%
-char **argv;%
-{%
-    int	c;%
-    extern int optind;%
-    extern char	*optarg;%
-    int errflg = 0;%
-    int totlines = 0;%
-%
-    /* Command-line options: */%
-    OPTS opts;%
-    opts.Vflg = FALSE;		/* variable col width */%
-    opts.Sflg = FALSE;		/* stretch output columns to fit */%
-    opts.Gutter = 1;		/* gutter width */%
-    opts.ColWidth = 0;		/* fixed col width */%
-    opts.Ncols = 0;		/* number of cols */%
-    opts.Width = 79;		/* output width */%
-    opts.Tabsize = 8;		/* tab size */%
-    opts.PageLen = 0;		/* page length */%
-    opts.ColSep[0] = '\0';	/* column separator string */%
-    opts.Leader = '\0';		/* leader char for column separation */%
-%
-    while ((c =	getopt (argc, argv, "vsg:c:n:w:l:L:t:T:")) != EOF) {%
-	switch	(c) {%
-	  case 'v':%
-	    if (opts.ColWidth != 0) errflg++;%
-	    opts.Vflg = TRUE;%
-	    break;%
-	  case 's':%
-	    opts.Sflg = TRUE;%
-	    break;%
-	  case 'c':%
-	    if (opts.Vflg == TRUE) errflg++;%
-	    opts.ColWidth = atoi(optarg);%
-	    if (opts.ColWidth < 1) errflg++;%
-	    break;%
-	  case 'g':%
-	    opts.Gutter = atoi(optarg);%
-	    if (opts.Gutter < 0) errflg++;%
-	    break;%
-	  case 'n':%
-	    opts.Ncols = atoi(optarg);%
-	    if (opts.Ncols < 0) errflg++;%
-	    break;%
-	  case 'w':%
-	    opts.Width = atoi(optarg);%
-	    if (opts.Width < 1) errflg++;%
-	    break;%
-	  case 'l':%
-	    opts.PageLen = atoi(optarg);%
-	    if (opts.PageLen < 1) errflg++;%
-	    break;%
-	  case 'T':%
-	    opts.Tabsize = atoi(optarg);%
-	    if (opts.Tabsize < 1) errflg++;%
-	    break;%
-	  case 'L':%
-	    opts.Leader = optarg[0];%
-	    break;%
-	  case 't':%
-	    strcpy(opts.ColSep, optarg);%
-	    break;%
-	  case '?':%
-	    errflg++;%
-	}%
-    }%
-    Opts = opts;		/* copy to global, so we know what was */%
-				/* actually user-specified and what we */%
-				/* computed */%
-    if (errflg)	{%
-	Usage();%
-	exit (2);%
-    }%
-    if (optind >= argc)%
-	totlines = ReadIn("-", &Lines); /* read stdin */%
-    else {%
-	for( ; optind < argc; optind++) {%
-	    totlines += ReadIn(argv[optind], &Lines); /* read text files */%
-	}%
-    }%
-    if (totlines > 0)%
-	Columnate(&Lines, &opts, totlines);%
-}%
-%
-Usage()%
-{%
-    fprintf(stderr,"\n\%
-Usage: %s [-cglnstvwLT] <files>\n\%
- Use '-' for stdin.\n\%
- Options:\n\%
- -v	variable-width columns (default: fixed-width)\n\%
- -s	spread columns to fit output width (default: don't spread)\n\%
- -g #	separate columns by a #-character 'gutter'.\n\%
- -c #	column width (size) (default: max line length of input)\n\%
- -n #	use # columns (default: program picks max # that will fit)\n\%
- -w #	output width is # characters/line (default: 80)\n\%
- -l #	page length is # lines (default: infinite)\n\%
- -L c	leader character is 'c' (default: space)\n\%
- -t s	use string \"s\" as separator (default: enough space to line up)\n\%
- -T #	use #-space tabs (default: 8)\n");%
-}%
END.colm.c
if (test -d column.c) then
  echo column.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f column.c) then
  echo 'Should I overwrite the existing version of column.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f column.c) then
  echo Overwriting column.c...
  else
  echo Creating column.c...
fi
sed 's/-//;s/%$//' << 'END.column.c' > column.c
-/*----------------------------------------------------------------------%
- * column.c - does the actual work of columnating the list of lines%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include <stdio.h>%
-#include "std.h"%
-#include "colm.h"%
-%
-extern int debug;%
-%
-static char SCCSId[] = "@(#)column.c	1.1 6/3/88 (MASSCOMP) 22:44:43";%
-%
-/* Returns success or failure. */%
-BOOLEAN%
-Columnate(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;			/* total number of text lines to columnate */%
-{%
-    /* First, check to make sure it's possible to columnate the output. */%
-    if (findmax(list, totlines) > opts->Width) {%
-	fprintf(stderr, "\%
-Error: Some input line is longer than the output width of %d chars.\n",%
-		opts->Width);%
-	exit(1);%
-    }%
-    if (!SinglePageCol(list, opts, totlines))%
-	return MultiPageCol(list, opts, totlines);%
-    else return TRUE;%
-}%
-%
-/* SinglePageCol returns TRUE or FALSE, according to whether the text */%
-/* will fit on the page. */%
-static BOOLEAN%
-SinglePageCol(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    int try_again = TRUE;%
-    while (try_again) {%
-	try_again = FALSE;%
-	%
-	if (opts->ColWidth > 0 && opts->Ncols > 0)%
-	    return FixedColumns(list, opts, totlines);%
-	if (opts->Vflg == TRUE)%
-	    return VarColumns(list, opts, totlines);%
-	if (opts->Ncols > 0 && opts->Sflg == TRUE  && opts->ColWidth == 0) {%
-	    opts->ColWidth = opts->Width / opts->Ncols;%
-	    return FixedColumns(list, opts, totlines);%
-	}%
-	/* We can figure out the column width by finding the largest */%
-	/* string.  Once we find that, we process again to pick up any */%
-	/* other options. */%
-	if (opts->ColWidth == 0) {%
-	    opts->ColWidth = findmax(list, -1) + opts->Gutter;%
-	    try_again = TRUE;%
-	}%
-	/* If we know the column width and the output width, we can */%
-	/* figure out the number of columns. */%
-	if (opts->ColWidth > 0 && opts->Width > 0 && opts->Ncols == 0) {%
-	    opts->Ncols = opts->Width / opts->ColWidth;%
-	    try_again = TRUE;%
-	}%
-    }%
-}%
-%
-/* Same return value as for SinglePageCol. */%
-/* FixedColumns() requires that ColWidth, NCols and Width be set. */%
-BOOLEAN%
-static FixedColumns(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    NODE *cols[MAX_COLS];	/* NODE pointers for each column */%
-    register int i,j;%
-    int outlines;		/* total # of output lines */%
-%
-    /* This is the easy case - just put out the lines. */%
-%
-    ASSERT(opts->ColWidth > 0 && opts->Ncols > 0);%
-    /* We only print an error message here if the user actually */%
-    /* specified (via capital-O Opts) a number of columns and width. */%
-    if (Opts.Ncols > 0 && Opts.ColWidth > 0 &&%
-	opts->ColWidth * opts->Ncols > opts->Width) {%
-	fprintf(stderr,%
-		"%d columns of %d characters won't fit in output width",%
-		opts->Ncols, opts->ColWidth);%
-	fprintf(stderr," of %d chars.\n", opts->Width);%
-	exit(3);%
-    }%
-    /* It's not always possible to form up proper columns from a given */%
-    /* number of input lines; 'proper' here means all columns even */%
-    /* except the last, which can be as short as one element.  For */%
-    /* instance, five text lines can't be formed into four columns. */%
-    /* But they can be formed into three columns of two each, except */%
-    /* the last column which will contain only one line. */%
-    /* Here we always opt for using fewer columns instead. */%
-    /* We spread the extra space (if any) out over all the columns. */%
-%
-    outlines = (totlines + opts->Ncols - 1) / opts->Ncols;%
-%
-    if ((totlines + outlines-1) / outlines != opts->Ncols) {%
-	int extraspace = opts->ColWidth%
-	    * (opts->Ncols - (totlines + outlines-1) / outlines);%
-	/* Here again, we only print the error message if the user */%
-	/* explicitly requested (via Opts) a number of columns.  If we */%
-	/* figured it out, we don't need to tell her that we guessed */%
-	/* wrong. */%
-	if (Opts.Ncols > 0) {%
-	    fprintf(stderr,"Can't form %d text lines into %d proper columns; ",%
-		    totlines, opts->Ncols);%
-	    fprintf(stderr,"using %d columns instead.\n",%
-		    (totlines + outlines-1) / outlines);%
-	}%
-	opts->Ncols = (totlines + outlines-1) / outlines;%
-	/* Only spread columns if cwidth wasn't explicitly specified. */%
-	if (Opts.ColWidth == 0 && opts->Sflg == TRUE)%
-	    opts->ColWidth += extraspace / opts->Ncols;%
-	return FixedColumns(list, opts, totlines);%
-    }%
-    if (opts->PageLen > 0 && outlines > opts->PageLen) return FALSE;%
-    for (i = 0; i < opts->Ncols; i++)%
-	cols[i] = findn(list, i * outlines);%
-%
-    for (j = 0; j < outlines; j++) {%
-	for (i = 0; i < opts->Ncols; i++) {%
-	    if (cols[i] != list) {%
-		Output(cols[i]->string, opts->ColWidth);%
-		if (i != opts->Ncols - 1 && cols[i+1] != list)%
-		    ToCol(opts->ColWidth * (i+1), opts);%
-		cols[i] = cols[i]->next;%
-	    }%
-	}%
-	OutNL();%
-    }%
-}%
-%
-BOOLEAN%
-static MultiPageCol(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    fprintf(stderr,"Can't do multi-page columnation (yet).\n");%
-    return FALSE;%
-}%
END.column.c
if (test -d lists.c) then
  echo lists.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f lists.c) then
  echo 'Should I overwrite the existing version of lists.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f lists.c) then
  echo Overwriting lists.c...
  else
  echo Creating lists.c...
fi
sed 's/-//;s/%$//' << 'END.lists.c' > lists.c
-/*----------------------------------------------------------------------%
- * These functions append to and search a doubly-linked, non-circular%
- * list of text lines.%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include <stdio.h>%
-#include "std.h"%
-#include "colm.h"%
-%
-extern int debug;%
-%
-static char SCCSId[] = "@(#)lists.c	1.1 6/3/88 (MASSCOMP) 22:44:45";%
-%
-/* Declare the empty line list: */%
-/* Note that this header node is NOT part of the list. */%
-NODE Lines = { &Lines, &Lines, 0, NULL };%
-%
-/* Append a new string to the list: */%
-append(str, list)%
-char *str;%
-NODE *list;%
-{%
-    register NODE *new;%
-%
-    ASSERT(str != NULL);%
-    ASSERT(list != NULL);%
-%
-    NEW(new, NODE, 1);		/* get a node */%
-    NEW(new->string, char, strlen(str) + 1); /* get string storage */%
-%
-    strcpy(new->string, str);	/* copy the string into the storage */%
-    new->length = strlen(str);	/* store the length, for speed */%
-%
-    new->next = list;		/* link it onto the end of the list. */%
-    new->prev = list->prev;%
-    new->prev->next = new;%
-    list->prev = new;%
-}%
-%
-/* Linearly search the next 'n' items of the list for longest string */%
-/* If n is negative, the search goes forever. */%
-int%
-findmax(list, n)%
-NODE *list;%
-int n;%
-{%
-    register NODE *current = list->next;%
-    NODE *longest = current;%
-%
-    ASSERT(list != NULL);%
-    ASSERT(list->next != NULL);%
-    ASSERT(list->prev != NULL);%
-%
-    for ( ; current != list && n != 0; current = current->next) {%
-        if (current->length > longest->length)%
-	    longest = current;%
-	if (n > 0) n--;%
-    }%
-    ASSERT(longest != NULL);%
-    return longest->length;%
-}%
-%
-/* Add up the lengths of all the strings in the list. */%
-/* If n > 0, look only at the next 'n' items. */%
-/* If n < 0, look through to the end. */%
-int%
-total_chars(list, n)%
-NODE *list;%
-int n;%
-{%
-    register NODE *current;%
-    int total = 0;%
-%
-    ASSERT(list != NULL);%
-    ASSERT(list->next != NULL);%
-    ASSERT(list->prev != NULL);%
-%
-    for (current = list->next; current != list && n != 0;%
-	 current = current->next) {%
-	total += current->length;%
-	if (n > 0) n--;%
-    }%
-    return total;%
-}%
-%
-NODE *%
-findn(list, n)%
-NODE *list;%
-int n;%
-{%
-    register NODE *current = list->next;%
-%
-    ASSERT(list != NULL);%
-    ASSERT(list->next != NULL);%
-    ASSERT(list->prev != NULL);%
-%
-    for ( ; current != list && n != 0; current = current->next, n--)%
-	;%
-    ASSERT(current != list);%
-    return current;%
-}%
END.lists.c
if (test -d output.c) then
  echo output.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f output.c) then
  echo 'Should I overwrite the existing version of output.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f output.c) then
  echo Overwriting output.c...
  else
  echo Creating output.c...
fi
sed 's/-//;s/%$//' << 'END.output.c' > output.c
-/*----------------------------------------------------------------------%
- * output - output routines for auto-columnator%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include "stdio.h"%
-#include "std.h"%
-#include "colm.h"%
-%
-static char SCCSId[] = "@(#)output.c	1.1 6/3/88 (MASSCOMP) 22:44:46";%
-%
-static OutCol = 0;		/* current output column */%
-%
-Output(s, maxlen)%
-char *s;%
-int maxlen;%
-{%
-    OutCol += printf("%.*s", maxlen, s);%
-}%
-%
-/* This ignores the opts right now. */%
-ToCol(tocol, opts)%
-int tocol;			/* column to move to (org 0) */%
-OPTS *opts;			/* how to move there */%
-{%
-    if (opts->ColSep[0] != '\0')%
-	printf("%s", opts->ColSep);%
-    if (opts->Leader == '\0') {	/* no leader, use spaces & tabs */%
-	while (OutCol < (tocol - tocol % opts->Tabsize)) {%
-	    putchar('\t');%
-	    OutCol += opts->Tabsize;%
-	    OutCol -= OutCol % opts->Tabsize;%
-	}%
-    }%
-    while (OutCol < tocol) {%
-	putchar(opts->Leader == '\0' ? ' ' : opts->Leader);%
-	OutCol++;%
-    }%
-}%
-%
-OutNL()%
-{%
-    putchar('\n');%
-    OutCol = 0;%
-}%
END.output.c
if (test -d readin.c) then
  echo readin.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f readin.c) then
  echo 'Should I overwrite the existing version of readin.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f readin.c) then
  echo Overwriting readin.c...
  else
  echo Creating readin.c...
fi
sed 's/-//;s/%$//' << 'END.readin.c' > readin.c
-/*----------------------------------------------------------------------%
- * ReadIn - read a file into a list of lines.%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include <stdio.h>%
-#include "std.h"%
-#include "colm.h"%
-%
-#define MAX_LEN 20000		/* maximum string length */%
-%
-extern int debug;%
-%
-static char SCCSId[] = "@(#)readin.c	1.1 6/3/88 (MASSCOMP) 22:44:47";%
-%
-ReadIn(fname, list)%
-char *fname;%
-NODE *list;%
-{%
-    char Instr[MAX_LEN];%
-    FILE *infile = NULL;%
-    int TotalLines = 0;		/* total # of lines read */%
-%
-    if (!strcmp(fname, "-"))%
-	infile = stdin;%
-    else if ((infile = fopen(fname, "r")) == NULL) {%
-	fprintf(stderr,"Can't open file %s\n.", fname);%
-	exit(9);%
-    }%
-    while (fgets(Instr, MAX_LEN, infile)) {%
-	if (*Instr == '\0') {%
-	    fprintf(stderr,%
-		    "Error: Null found in supposedly line-oriented data.\n");%
-	    exit(2);%
-	}%
-	TotalLines++;%
-	Instr[strlen(Instr)-1] = '\0'; /* strip newline */%
-	append(Instr, list); /* add it to the list */%
-	ASSERT(list->prev != NULL);%
-    }%
-    return TotalLines;%
-}%
END.readin.c
if (test -d vcolumn.c) then
  echo vcolumn.c is an existing directory.  Cannot overwrite it.
  exit 2
fi
if (test -f vcolumn.c) then
  echo 'Should I overwrite the existing version of vcolumn.c (y/n)?  \c'
  read response
  if (test $response != y) then exit 99
  fi
fi
if (test -f vcolumn.c) then
  echo Overwriting vcolumn.c...
  else
  echo Creating vcolumn.c...
fi
sed 's/-//;s/%$//' << 'END.vcolumn.c' > vcolumn.c
-/*----------------------------------------------------------------------%
- * vcolumn.c - columnates with variable-size columns%
- * Copyright c. 1988, Gary Oberbrunner.%
- * This program may be freely redistributed providing that this source code%
- * and the accompanying copyright notice are preserved intact.%
- *----------------------------------------------------------------------%
- */%
-%
-#include <stdio.h>%
-#include "std.h"%
-#include "colm.h"%
-%
-extern int debug;%
-void ClearWidths();%
-%
-static char SCCSId[] = "@(#)vcolumn.c	1.2 6/3/88 (MASSCOMP) 23:11:49";%
-%
-BOOLEAN%
-    VarColumns(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    ASSERT(Opts.ColWidth == 0);%
-    /* Only auto-columnate if she didn't say how many columns, or if */%
-    /* the requested number of columns fails. */%
-    if (Opts.Ncols == 0 || ManVarColumns(list, opts, totlines) == FALSE)%
-	AutoVarColumns(list, opts, totlines);%
-}%
-%
-BOOLEAN%
-    ManVarColumns(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    int outlines;%
-    int widths[MAX_COLS];	/* column-width table */%
-    register NODE *current;%
-    register int line, col;%
-    int twidth = 0;%
-    %
-    ASSERT(opts->Ncols > 0);%
-    outlines = (totlines + opts->Ncols - 1) / opts->Ncols;%
-    %
-    ClearWidths(widths, MAX_COLS);%
-    for (current = list->next, col = 0, line=0;%
-	 current != list && totlines != 0;%
-	 current = current->next, totlines--) {%
-	if (current->length > widths[col])%
-	    widths[col] = current->length;%
-	/* Do next line, and if at bottom start next column */%
-	if (++line >= outlines) {%
-	    col++;%
-	    line = 0;%
-	}%
-    }%
-    for (col = 0; col < opts->Ncols; col++)%
-	if (col != opts->Ncols -1)%
-	    widths[col] += opts->Gutter;%
-    twidth += widths[col];%
-    if (twidth > opts->Width) {%
-	fprintf(stderr,"\%
-%d text columns won't fit into output width of %d chars; %d chars too wide.\n",%
-		opts->Ncols, opts->Width, twidth - opts->Width);%
-	return FALSE;%
-    }%
-    OutVCols(list, opts, totlines, outlines, widths);%
-    return TRUE;%
-}%
-%
-BOOLEAN%
-    AutoVarColumns(list, opts, totlines)%
-NODE *list;%
-OPTS *opts;%
-int totlines;%
-{%
-    int widths[MAX_COLS];	/* column-width table */%
-    register int outlines;%
-    int avglen;%
-    %
-    /* We start with the smallest possible number of output lines and */%
-    /* successively increase by ones until it works. */%
-    %
-    /* First, compute the smallest possible outlines: */%
-    outlines = max(1, total_chars(list, totlines) / opts->Width);%
-    %
-    while (1) {%
-	ASSERT(outlines <= totlines); /* runaway check */%
-	ClearWidths(widths, MAX_COLS);%
-	if (VariCol(list, opts, totlines, outlines, widths) == TRUE)%
-	    break;%
-	outlines++;%
-    }%
-    /* Now opts->Ncols is correct, and VariCol has filled in widths[]. */%
-    OutVCols(list, opts, totlines, outlines, widths);%
-    return TRUE;%
-}%
-static void%
-    ClearWidths(w, nc)%
-int w[];%
-int nc;%
-{%
-    ASSERT (nc > 0);%
-    while (nc--)%
-	w[nc] = 0;%
-}%
-%
-static BOOLEAN%
-    VariCol(list, opts, textlines, outlines, widths)%
-NODE *list;%
-OPTS *opts;%
-int textlines;%
-int outlines;%
-int widths[];%
-{%
-    register int col;		/* current column */%
-    register int line;		/* current out line */%
-    register int twidth = 0;%
-    register NODE *current;%
-    %
-    for (current = list->next, col = 0, line=0;%
-	 current != list && textlines != 0;%
-	 current = current->next, textlines--) {%
-	if (current->length > widths[col])%
-	    widths[col] = current->length;%
-	/* Do next line, and if at bottom start next column */%
-	if (++line >= outlines) {%
-	    col++;%
-	    line = 0;%
-	}%
-    }%
-    if (line != 0) col++;%
-    opts->Ncols = col;%
-    for (col = 0; col < opts->Ncols; col++) {%
-	if (col != opts->Ncols -1)%
-	    widths[col] += opts->Gutter;%
-	twidth += widths[col];%
-    }%
-    if (twidth <= opts->Width) { /* we made it */%
-	/* Partition the extra space as evenly as possible */%
-	int extra_chars = opts->Width - twidth;%
-	while (extra_chars > 0 && opts->Ncols > 1 && opts->Sflg == TRUE)%
-	    for (col = 0; col < opts->Ncols-1 && extra_chars > 0; col++) {%
-		widths[col]++;%
-		extra_chars--;%
-	    }%
-	return (TRUE);%
-    }%
-    return FALSE;%
-}%
-%
-static OutVCols(list, opts, textlines, outlines, widths)%
-NODE *list;%
-OPTS *opts;%
-int textlines;%
-int outlines;%
-int widths[];%
-{%
-    register int col, line;%
-    int ccol;			/* current character column position */%
-    NODE *cols[MAX_COLS];%
-    %
-    /* Get pointers to text lines, one for each column */%
-    for (col = 0; col < opts->Ncols; col++) {%
-	cols[col] = findn(list, outlines * col);%
-    }%
-    for (line = 0; line < outlines; line++) {%
-	ccol = 0;%
-	for (col = 0; col < opts->Ncols; col++) {%
-	    if (cols[col] != list) {%
-		Output(cols[col]->string, widths[col]);%
-		if (col != opts->Ncols - 1 && cols[col+1] != list)%
-		    ToCol(ccol += widths[col], opts);%
-		cols[col] = cols[col]->next;%
-	    }%
-	}%
-	OutNL();%
-    }%
-}%
END.vcolumn.c
exit 0
#-------------------------------- end of archive; cut here -------------------
-- 
Remember,			Truth is not beauty;      (617)692-6200x2445
Information is not knowledge;	Beauty is not love;	  Gary   Oberbrunner
Knowledge is not wisdom;	Love is not music;	  ...!masscomp!garyo
Wisdom is not truth;		Music is the best. - FZ   ....garyo@masscomp

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.