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.