Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: Notesfiles $Revision: 1.6.2.17 $; site ea.UUCP
Path: utzoo!watmath!clyde!cbosgd!ihnp4!inuxc!pur-ee!uiucdcs!ea!jejones
From: jejones@ea.UUCP
Newsgroups: net.micro.6809
Subject: columnar output hack
Message-ID: <7300035@ea.UUCP>
Date: Thu, 20-Dec-84 18:57:00 EST
Article-I.D.: ea.7300035
Posted: Thu Dec 20 18:57:00 1984
Date-Received: Fri, 28-Dec-84 03:50:20 EST
Lines: 304
Nf-ID: #N:ea:7300035:000:6388
Nf-From: ea!jejones Dec 20 17:57:00 1984
Yet another possibly useful tool: this one splits out fields from input
lines and writes them out in columnar fashion. Admittedly this one, like
the sort that preceded it, isn't particularly OS-9 or 6809-specific, but
then there are places that lock up net.sources, and I want the OS-9 users
out there to get these tools.
James Jones
------------------------------TIARA HERE------------------------------
/*
* column -- print with fields justified and columnized
*
* usage: column [] [ ... ] [ ...]
* where has the form
* /[]
* and can be either 'l' or 'r'.
* (Upper or lower case will do.)
*
* options: -c= use the as a field separator
* -l assume the output lines have maximum length
*
*
* semantics: reads files with the specified pathnames and prints the
* fields selected from each line so that they fit on a line
* at most characters long, with each field lined up
* in columnar fashion. Fields longer than their
* are truncated. Spaces left over are divided evenly
* between columns.
*
* defaults: field separator defaults to space, to 80.
* If no fields are specified, then 1/l is assumed.
* Justification defaults to left-justification.
* If no pathnames are specified, standard input is read.
*
* limits: Lines are truncated at MAXLINE characters.
* We can output at most MAXFIELDS fields, and read
* at most MAXFILES files.
* We are currently stupid about tabs and backspaces
* when we figure out what fits on a line.
*/
#include
#include
#include
#define MAXLINE 256
#define MAXFILES 20
#define MAXFIELDS 10
#define error(msg) {fprintf(stderr, "column: %s\n", (msg)); exit(1);}
#define Space(size) {int i; for (i = 0; i < (size); i++) putchar(' ');}
#define DELIM 'c'
#define LENGTH 'l'
#define LJUST 'L'
#define RJUST 'R'
typedef struct {
int f_no;
int f_maxlen;
char f_justify;
int f_gutter;
char *f_pos;
int f_trulen;
} FldDesc;
FldDesc LineFields[MAXFIELDS],
*FldSeq[MAXFIELDS];
int NFields;
char *Input[MAXFILES];
int NInputs, CurrPath;
FILE *CurrSource;
char Delim = ' ';
int Length = 80;
main(argc, argv)
int argc;
char *argv[];
{
int i;
char Line[MAXLINE];
char *InLine();
bool OK, DoOpt(), DoFile(), InitLayout(), StartRead();
OK = TRUE;
for (i = 1; i < argc; i++) {
if (*argv[i] == '-')
OK &= DoOpt(argv[i]);
else if (isdigit(*argv[i]))
OK &= DoFld(argv[i]);
else
OK &= DoFile(argv[i]);
}
if (!OK || !InitLayout() || !StartRead())
exit(1);
while (InLine(Line) != NULL)
Columnize(Line);
}
bool
DoOpt(OpString)
char *OpString;
{
switch (*(OpString + 1)) {
case DELIM:
if (*(OpString + 2) != '=')
error("invalid delimiter specification");
Delim = *(OpString + 3);
break;
case LENGTH:
if ((Length = atoi(OpString + 2)) <= 0)
error("invalid line length");
break;
default:
fprintf(stderr, "column: invalid option %c\n", *(OpString + 1));
return(FALSE);
}
return(TRUE);
}
bool
DoFld(FldString)
char *FldString;
{
FldDesc *NewFld;
FldSeq[NFields] = NewFld = &LineFields[NFields];
if ((NewFld->f_no = atoi(FldString)) <= 0)
error("invalid field number");
while (isdigit(*(FldString++)))
;
if (*(FldString - 1) != '/')
error("invalid field specification");
if ((NewFld->f_maxlen = atoi(FldString)) <= 0)
error("invalid field width");
while (isdigit(*(FldString++)))
;
switch (toupper(*(FldString - 1))) {
case RJUST:
NewFld->f_justify = RJUST;
break;
case '\0':
case LJUST:
NewFld->f_justify = LJUST;
break;
default:
error("invalid justification");
}
NFields++;
return(TRUE);
}
/*
* routines to hide the multiplicity of input files from the main
* algorithm -- DoFile, StartRead, and InLine.
*/
bool
DoFile(PathName)
char *PathName;
{
if (NInputs >= MAXFILES)
error("too many input files");
Input[NInputs++] = PathName;
return(TRUE);
}
bool
StartRead()
{
if (NInputs > 0) {
if ((CurrSource = fopen(Input[0], "r")) == NULL) {
fprintf(stderr, "sort: can't open %s\n", Input[0]);
return(FALSE);
}
} else
CurrSource = stdin;
return(TRUE);
}
char *
InLine(Buffer)
char *Buffer;
{
char *result;
while ((result = fgets(Buffer, MAXLINE, CurrSource)) == NULL) {
fclose(CurrSource);
if (++CurrPath >= NInputs)
return(NULL);
if ((CurrSource = fopen(Input[CurrPath], "r")) == NULL) {
fprintf(stderr, "sort: can't open %s\n",
Input[CurrPath]);
exit(1);
}
}
return(result);
}
bool
InitLayout()
{
int i, totlen, gap, leftover;
int Precede();
if (NFields == 0) {
FldSeq[0] = &LineFields[0];
LineFields[0].f_no = 1;
LineFields[0].f_maxlen = Length;
LineFields[0].f_justify = LJUST;
} else if (NFields > 1) {
totlen = 0;
for (i = 0; i < NFields; i++)
totlen += LineFields[i].f_maxlen;
if ((gap = (Length - totlen) / (NFields - 1)) < 1)
error("fields too big for output line");
leftover = (Length - totlen) % (NFields - 1);
for (i = 0; i < NFields - 1; i++)
LineFields[i].f_gutter = gap + (i < leftover);
qsort(FldSeq, NFields, sizeof(FldDesc *), Precede);
}
LineFields[NFields - 1].f_gutter = 0;
return(TRUE);
}
int
Precede(f1, f2)
FldDesc **f1, **f2;
{
return ((*f1)->f_no - (*f2)->f_no);
}
Columnize(Line)
char *Line;
{
char *Field;
int i, CurrField, FScan, FLen;
bool ShouldOutput;
Field = Line;
Field[strlen(Field) - 1] = Delim;
for (CurrField = 1, FScan = 0; FScan < NFields; CurrField++) {
ShouldOutput = CurrField >= FldSeq[FScan]->f_no;
if (ShouldOutput)
FldSeq[FScan]->f_pos = Field;
FLen = 0;
if (*Field != '\0') {
while (*(Field++) != Delim)
FLen++;
*(Field - 1) = '\0';
}
if (ShouldOutput) {
FldSeq[FScan]->f_trulen = FLen;
FScan++;
}
}
for (FScan = 0; FScan < NFields; FScan++)
PrintField(&LineFields[FScan]);
putchar('\n');
}
PrintField(RefFld)
FldDesc *RefFld;
{
if (RefFld->f_trulen > RefFld->f_maxlen) {
(RefFld->f_pos)[RefFld->f_maxlen] = '\0';
RefFld->f_trulen = RefFld->f_maxlen;
}
switch (RefFld->f_justify) {
case RJUST:
Space(RefFld->f_maxlen - RefFld->f_trulen);
fputs(RefFld->f_pos, stdout);
break;
case LJUST:
fputs(RefFld->f_pos, stdout);
Space(RefFld->f_maxlen - RefFld->f_trulen);
break;
}
Space(RefFld->f_gutter);
}