[mod.sources] v06i016: halign - line up columns

sources-request@mirror.UUCP (06/23/86)

Submitted by: talcott!mcgill-vision!garfield!mouse (der Mouse)
Mod.sources: Volume 6, Issue 16
Archive-name: halign

Here is a  handy  little program I wrote...it  produces nicely  lined-up
columns from messy out-of-alignment columns.  For example, it can turn

3 9
9 81
81 6561
6561 43046721
43046721 (overflow)

into

       3          9
       9         81
      81       6561
    6561   43046721
43046721 (overflow)

Read the man page for a full description.

--------------------------------cut here--------------------------------
#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Wed Jun 11 04:53:03 1986
# Run this through sh to create:
#	halign.1
#	halign.c
echo x - halign.1 \(2051 characters\)
sed 's/^X//' > halign.1 << \SHAR_EOF
X.TH HALIGN 1 "11 June 1986"
X.UC 4
X.SH NAME
Xhalign - produce lined-up columns
X.SH SYNOPSIS
X.nf
X.ft B
Xhalign [lrc][\fIn\fP] ...
X.PP
X.fi
X.SH DESCRIPTION
X\fIHalign\fP is a program to produce nicely lined-up columns from almost any
Xsort of columnized input.  For example, if you have a program which prints
Xlines with two numbers on each line, halign can adjust things so they line up
Xnicely.  For example, let us suppose you have a program (here called `foo')
Xwhich produces the following output:
X.PP
X.in +8
X.nf
X% foo
X3 9
X9 81
X81 6561
X6561 43046721
X43046721 (overflow)
X.PP
X.fi
XNow, to get things lined up and right-justified:
X.PP
X.in +8
X.nf
X% foo | halign r r
X       3          9
X       9         81
X      81       6561
X    6561   43046721
X43046721 (overflow)
X.PP
X.fi
XEach argument to halign must be a letter followed by an optional number.  The
Xletter specifies how the column is to be aligned; \fIl\fP specifies that the
Xcolumn is to be set flush left, \fIr\fP indicates flush right, and \fIc\fP
Xspecifies centering.  Of course, centering cannot always be exact; if unable
Xto center an entry exactly, halign will put the extra space on the right.  If
Xthe number is given, it is a minimum width for the column; normally, a column
Xis only as wide as necessary to contain the widest entry in that column.  For
Xexample, \fIl10\fP specifies a column at least 10 characters wide (though it
Xwill be wider if there is an entry wider than 10 characters), with the entry
Xset at the left and padded on the right (if necessary).
X.SH NOTES
XHalign must of course read all of its input before printing anything; the
Xinput is stored in files on /tmp (one file per column).  Because these files
Xare all kept open at once, halign will break if more than NFILE-3 (currently
X17 on most UNIX systems) columns are specified.
X.SH BUGS
XHalign thinks control characters, such as backspace and escape, are normal
Xprinting characters, so the columns may not line up if the entries contain
Xsuch characters.
X.SH AUTHOR
Xder Mouse (Mike Parker, mcgill-vision!mouse), September, 1985.
SHAR_EOF
if test 2051 -ne "`wc -c halign.1`"
then
echo shar: error transmitting halign.1 \(should have been 2051 characters\)
fi
echo x - halign.c \(6462 characters\)
sed 's/^X//' > halign.c << \SHAR_EOF
X/*
X * halign - program to produce lined-up columns
X *
X * Halign reads input in the form of columns of data separated by whitespace;
X *  the output is similar except that all the columns line up.  This was
X *  inspired by the common uses of the \halign command in TeX; knowing how
X *  TeX's \halign command works will make this program almost self-evident.
X *
X * Usage is
X *
X *	halign [clr][n] ...
X *
X *  where each argument corresponds to one column in the input.
X *
X * The letter indicates how the column is to be justified; r indicates
X *  flush-right, l indicates flush-left, and c indicates centered.  Of
X *  course, centering cannot be perfect without half-character resolution; if
X *  an item cannot be centered exactly the extra space will go on the right.
X *
X * The number n, if given, indicates a minimum width for the column.  The
X *  default is to make the column just wide enough to contain the widest
X *  entry; if this entry is narrower than n the column will be n characters
X *  wide anyway.
X *
X * Halign always puts one space between columns on output.
X *
X * All adjusting is done with spaces; if tabs are desired pipe the output
X *  through /usr/ucb/unexpand -a.
X *
X * Examples:
X *
X *	% cat x
X *	root 0 10 / /bin/csh
X *	mailer 0 10 / /bin/csh
X *	daemon 1 666 / 
X *	uucp 66 1 /usr/spool/uucppublic /usr/lib/uucp/uucico
X *	wnj 8 10 /u1/guest/wnj /bin/csh
X *	mckusick 9 10 /u1/guest/mckusick /bin/csh
X *	% halign l l l l l < x
X *	root     0  10  /                     /bin/csh            
X *	mailer   0  10  /                     /bin/csh            
X *	daemon   1  666 /                                         
X *	uucp     66 1   /usr/spool/uucppublic /usr/lib/uucp/uucico
X *	wnj      8  10  /u1/guest/wnj         /bin/csh            
X *	mckusick 9  10  /u1/guest/mckusick    /bin/csh            
X *	% halign l r5 r5 c c < x
X *	root         0    10           /                 /bin/csh      
X *	mailer       0    10           /                 /bin/csh      
X *	daemon       1   666           /                               
X *	uucp        66     1 /usr/spool/uucppublic /usr/lib/uucp/uucico
X *	wnj          8    10     /u1/guest/wnj           /bin/csh      
X *	mckusick     9    10  /u1/guest/mckusick         /bin/csh      
X *
X * Halign must of course read to the end of its input before generating any
X *  output, so that it knows how wide the columns must be.  The input column
X *  entries are copied into temporary files (on /tmp).
X *
X * The current incarnation cannot deal with more than about 17 columns; this
X *  is because a separate temporary file is used for each column, so not more
X *  than NFILE-3 (3 for stdin/stdout/stderr) columns will work.
X *
X * Copyright 1985 by Mike Parker.  Permission is granted for redistribution
X *  of this code, or modified versions of it, for any purpose as long as this
X *  notice remains intact and that no additional restrictions are placed on
X *  further redistribution.  I have tried to make sure that this program
X *  functions as the above description indicates, but I make no guarantees
X *  that this code does anything useful, or even that it does not do anything
X *  harmful.
X *
X * If you find any bugs I would appreciate hearing, especially if you also
X *  fix them.  Write to
X *	{ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/file.h>
X
Xchar *malloc();
Xchar *realloc();
X#define NEW(type) ((type *) malloc(sizeof(type)))
X#define OLD(x) free((char *) x)
X
Xchar **argvec;
X
Xtypedef struct _spec {
X	  char spec;
X	  int tfd;
X	  FILE *tf;
X	  char *buf;
X	  int maxwidth; } SPEC;
X
Xint errs;
Xint ncols;
Xint nlines;
XSPEC *spec;
Xchar tfilename[80];
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X int i;
X int j;
X int k;
X char *cp;
X char *dp;
X char c;
X int inspace;
X int colwidth;
X
X argvec = av;
X errs = 0;
X ncols = ac - 1;
X if (ncols <= 0)
X  { fprintf(stderr,"Usage: %s [clr][n] [clr][n] ...\n",argvec[0]);
X    exit(1);
X  }
X spec = (SPEC *) malloc(ncols*sizeof(SPEC));
X sprintf(tfilename,"/tmp/halign.%d",getpid());
X av ++;
X for (i=0;i<ncols;i++)
X  { spec[i].maxwidth = 0;
X    switch (av[i][0])
X     { case 'c':
X       case 'l':
X       case 'r':
X	  if (av[i][1])
X	   { spec[i].maxwidth = atoi(av[i]+1);
X	   }
X	  spec[i].spec = av[i][0];
X	  unlink(tfilename);
X	  spec[i].tfd = open(tfilename,O_RDWR|O_CREAT|O_TRUNC,0644);
X	  unlink(tfilename);
X	  if (spec[i].tfd < 0)
X	   { fprintf(stderr,"%s: cannot open temporary file %s: ",
X						argvec[0],tfilename);
X	     perror(0);
X	     errs ++;
X	   }
X	  break;
X       default:
X	  fprintf(stderr,
X		"%s: `%c' is not a valid specification (c, l, or r)\n",
X							argvec[0],av[i][0]);
X	  errs ++;
X	  break;
X     }
X  }
X for (i=0;i<ncols;i++)
X  { if (spec[i].tfd >= 0)
X     { spec[i].tf = fdopen(spec[i].tfd,"r+");
X       if (! spec[i].tf)
X	{ fprintf(stderr,"%s: cannot fdopen, serious failure: ",argvec[0]);
X	  perror(0);
X	  errs ++;
X	}
X     }
X  }
X if (errs)
X  { exit(1);
X  }
X nlines = 0;
X i = 0;
X inspace = 1;
X colwidth = 0;
X while (1)
X  { c = getchar();
X    if (feof(stdin))
X     { if ((i > 0) || (colwidth > 0))
X	{ c = '\n';
X	}
X       else
X	{ break;
X	}
X     }
X    else if (isspace(c))
X     { if (! inspace)
X	{ inspace = 1;
X	  if (colwidth > spec[i].maxwidth)
X	   { spec[i].maxwidth = colwidth;
X	   }
X	  if (i < ncols-1)
X	   { putc('\n',spec[i].tf);
X	     i ++;
X	   }
X	  colwidth = 0;
X	}
X       if (c == '\n')
X	{ for (;i<ncols;i++)
X	   { putc('\n',spec[i].tf);
X	   }
X	  nlines ++;
X	  i = 0;
X	  colwidth = 0;
X	  inspace = 1;
X	}
X     }
X    else
X     { putc(c,spec[i].tf);
X       colwidth ++;
X       inspace = 0;
X     }
X  }
X for (i=0;i<ncols;i++)
X  { fseek(spec[i].tf,0L,0);
X    spec[i].buf = malloc(spec[i].maxwidth+2);
X  }
X for (;nlines>0;nlines--)
X  { for (i=0;i<ncols;i++)
X     { fgets(spec[i].buf,spec[i].maxwidth+2,spec[i].tf);
X       j = strlen(spec[i].buf);
X       if (j > 0)
X	{ spec[i].buf[--j] = '\0';
X	}
X       k = spec[i].maxwidth - j;
X       cp = spec[i].buf;
X       cp[spec[i].maxwidth] = '\0';
X       spacefill(cp+j,k);
X       switch (spec[i].spec)
X	{ case 'l':
X	     break;
X	  case 'c':
X	     k /= 2;
X	     /* fall through */
X	  case 'r':
X	     cp += j;
X	     dp = cp + k;
X	     for (;j>0;j--)
X	      { *--dp = *--cp;
X	      }
X	     for (;k>0;k--)
X	      { *--dp = ' ';
X	      }
X	     break;
X	}
X       if (i)
X	{ putchar(' ');
X	}
X       fputs(spec[i].buf,stdout);
X     }
X    putchar('\n');
X  }
X}
X
Xspacefill(ptr,nb)
Xregister char *ptr;
Xregister int nb;
X{
X for (;nb>0;nb--)
X  { *ptr++ = ' ';
X  }
X}
SHAR_EOF
if test 6462 -ne "`wc -c halign.c`"
then
echo shar: error transmitting halign.c \(should have been 6462 characters\)
fi
exit 0
# end of shell archive