home *** CD-ROM | disk | FTP | other *** search
- Subject: v16i087: A columnation program
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- 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
-
-