newform.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14 */
/* FUNCTION PAGE INDEX
Function Page Description
append 16 Append chars to end of line.
begtrunc 16 Truncate characters from beginning of line.
center 5 Center text in the work area.
cnvtspec 7 Convert tab spec to tab positions.
endtrunc 16 Truncate chars from end of line.
inputtabs 17 Expand according to input tab specs.
main 3 MAIN
inputn 5 Read a command line option number.
options 4 Process command line options.
outputtabs 19 Contract according to output tab specs.
prepend 16 Prepend chars to line.
process 15 Process one line of input.
readline 14 Read one line from the file.
readspec 12 Read a tabspec from a file.
sstrip 18 Strip SCCS SID char from beginning of line.
sadd 18 Add SCCS SID chars to end of line.
type 14 Determine type of a character. */
#include <stdio.h>
#define MAXOPTS 50
#define NCOLS 512
#define MAXLINE 512
#define NUMBER '0'
#define LINELEN 80
int tabtbl[500] = { /* Table containing tab stops */
1,9,17,25,33,41,49,57,65,73,0,
/* Default tabs */
1,10,16,36,72,0, /* IBM 370 Assembler */
1,10,16,40,72,0, /* IBM 370 Assembler (alt.) */
1,8,12,16,20,55,0, /* COBOL */
1,6,10,14,49,0, /* COBOL (crunched) */
1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67,0,
/* COBOL (crunched, many cols.) */
1,7,11,15,19,23,0, /* FORTRAN */
1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,0,
/* PL/1 */
1,10,55,0, /* SNOBOL */
1,12,20,44,0 }, /* UNIVAC Assembler */
*nexttab = &tabtbl[87], /* Pointer to next empty slot */
*spectbl[40] = { /* Table of pointers into tabtbl */
&tabtbl[0], /* Default specification */
&tabtbl[11], /* -a specification */
&tabtbl[17], /* -a2 specification */
&tabtbl[23], /* -c specification */
&tabtbl[30], /* -c2 specification */
&tabtbl[36], /* -c3 specification */
&tabtbl[54], /* -f specification */
&tabtbl[61], /* -p specification */
&tabtbl[78], /* -s specification */
&tabtbl[82] }, /* -u specification */
savek; /* Stores char count stripped from front of line. */
int nextspec = 10, /* Index to next slot */
sitabspec = -1, /* Index to "standard input" spec. */
effll = 80, /* Effective line length */
optionf = 0, /* 'f' option set */
soption = 0, /* 's' option used. */
files = 0, /* Number of input files */
kludge = 0, /* Kludge to allow reread of 1st line */
okludge = 0, /* Kludge to indicate reading "o" option*/
lock = 0; /* Lock to prevent file indirection */
char pachar = ' ', /* Prepend/append character */
work[3*NCOLS+1], /* Work area */
*pfirst, /* Pointer to beginning of line */
*plast, /* Pointer to end of line */
*wfirst = &work[0], /* Pointer to beginning of work area */
*wlast = &work[3*NCOLS], /* Pointer to end of work area */
siline[NCOLS], /* First standard input line */
savchr[8], /* Holds char stripped from line start */
format[80] = "-8", /* Array to hold format line */
*strcpy(); /* Eliminates a warning by 'lint'. */
struct f {
char option;
int param;
} optl[MAXOPTS], /* List of command line options */
*flp = optl; /* Pointer to next open slot */
main(argc,argv) /* Main procedure */
int argc; /* Count of command line arguments */
char **argv; /* Array of pointers to arguments */
{
char *scan; /* String scan pointer */
FILE *fp; /* Pointer to current file */
options(argc,argv);
if (optionf) /* Write tab spec format line. */
{fputs("<:t",stdout);
fputs(format,stdout);
fputs(" d:>\n",stdout);
}
if (files) {
while (--argc) {
scan = *++argv;
if (*scan != '-') {
if ((fp = fopen(scan,"r")) == NULL) {
fprintf(stderr,
"newform: can't open %s\n",scan);
exit(1);
}
process(fp);
fclose(fp);
}
}
}
else {
process(stdin);
}
exit(0);
}
options(argc, argv) /* Process command line options */
register int argc; /* Count of arguments */
register char **argv; /* Array of pointers to arguments */
{
int n; /* Temporary number holder */
register char *scan, /* Pointer to individual option strings */
c; /* Option character */
/* changes to option parsing includes checks for exceeding */
/* initial buffer sizes */
while (--argc > 0) {
scan = *++argv;
if (*scan++ == '-') {
switch (c = *scan++) {
case 'a':
flp->option = 'a';
flp->param = inputn(scan);
if (flp->param <=NCOLS)
flp++;
else {
fprintf(stderr,"newform: prefix request larger than buffer, %d\n", NCOLS);
exit(1);
}
break;
case 'b':
case 'e':
flp->option = c;
flp->param = inputn(scan);
flp++;
break;
case 'p':
flp->option = 'p';
flp->param = inputn(scan);
if (flp->param <=NCOLS)
flp++;
else {
fprintf(stderr,"newform: prefix request larger than buffer, %d\n", NCOLS);
exit(1);
}
break;
case 'c':
flp->option = 'c';
flp->param = *scan ? *scan : ' ';
flp++;
break;
case 'f':
flp->option = 'f';
optionf++;
flp++;
break;
case 'i':
flp->option = 'i';
flp->param = cnvtspec(scan);
flp++;
break;
case 'o':
if(*scan=='-' && *(scan+1)=='0' && *(scan+2)=='\0')break;
/* Above allows the -o-0 option to be ignored. */
flp->option = 'o';
strcpy(format,scan);
okludge++;
flp->param = cnvtspec(scan);
okludge--;
if(flp->param == 0) strcpy(format,"-8");
flp++;
break;
case 'l':
flp->option = 'l';
flp->param = ((n = inputn(scan)) ? n : 72);
if (flp->param <= (3*NCOLS))
flp++;
else {
fprintf(stderr, "newform: line length request larger than buffer, %d \n", (3*NCOLS));
exit(1);
}
break;
case 's':
flp->option = 's';
flp++;
soption++;
break;
default:
goto usageerr;
}
}
else
files++;
}
return;
usageerr:
fprintf(stderr,"usage: newform [-s] [-itabspec] [-otabspec] ");
fprintf(stderr,"[-pn] [-en] [-an] [-f] [-cchar]\n\t\t");
fprintf(stderr,"[-ln] [-bn] [file ...]\n");
exit(1);
}
/* _________________________________________________________________ */
int inputn(scan) /* Read a command option number */
register char *scan; /* Pointer to string of digits */
{
int n; /* Number */
char c; /* Character being scanned */
n = 0;
while ((c = *scan++) >= '0' && c <= '9')
n = n * 10 + c - '0';
return(n);
}
/* _________________________________________________________________ */
center() /* Center the text in the work area. */
{
char *tfirst, /* Pointer for moving buffer down */
*tlast, /* Pointer for moving buffer up */
*tptr; /* Temporary */
if (plast - pfirst > MAXLINE) {
fprintf(stderr,"newform: internal line too long\n");
exit(1);
}
if (pfirst < &work[NCOLS]) {
tlast = plast + (&work[NCOLS] - pfirst);
tptr = tlast;
while (plast >= pfirst) *tlast-- = *plast--;
pfirst = ++tlast;
plast = tptr;
}
else {
tfirst = &work[NCOLS];
tptr = tfirst;
while (pfirst <= plast) *tfirst++ = *pfirst++;
plast = --tfirst;
pfirst = tptr;
}
}
int cnvtspec(p) /* Convert tab specification to tab positions. */
register char *p; /* Pointer to spec string. */
{
int state, /* DFA state */
spectype, /* Specification type */
number[40], /* Array of read-in numbers */
tp, /* Pointer to last number */
ix; /* Temporary */
int tspec=0; /* Tab spec pointer */
char c, /* Temporary */
*stptr, /* Pointer to stdin */
*filep, /* Pointer to file name */
type(), /* Function */
*readline(); /* Function */
FILE *fopen(), /* File open routine */
*fp; /* File pointer */
state = 0;
while (state >= 0) {
c = *p++;
switch (state) {
case 0:
switch (type(c)) {
case '\0':
spectype = 0;
state = -1;
break;
case NUMBER:
state = 1;
tp = 0;
number[tp] = c - '0';
break;
case '-':
state = 3;
break;
default:
goto tabspecerr;
}
break;
case 1:
switch (type(c)) {
case '\0':
spectype = 11;
state = -1;
break;
case NUMBER:
state = 1;
number[tp] = number[tp] * 10 + c - '0';
break;
case ',':
state = 2;
break;
default:
goto tabspecerr;
}
break;
case 2:
if (type(c) == NUMBER) {
state = 1;
number[++tp] = c - '0';
}
else
goto tabspecerr;
break;
case 3:
switch (type(c)) {
case '-':
state = 4;
break;
case 'a':
state = 5;
break;
case 'c':
state = 7;
break;
case 'f':
state = 10;
break;
case 'p':
state = 11;
break;
case 's':
state = 12;
break;
case 'u':
state = 13;
break;
case NUMBER:
state = 14;
number[0] = c - '0';
break;
default:
goto tabspecerr;
}
break;
case 4:
if (c == '\0') {
spectype = 12;
state = -1;
}
else {
filep = --p;
spectype = 13;
state = -1;
}
break;
case 5:
if (c == '\0') {
spectype = 1;
state = -1;
}
else if (c == '2')
state = 6;
else
goto tabspecerr;
break;
case 6:
if (c == '\0') {
spectype = 2;
state = -1;
}
else
goto tabspecerr;
break;
case 7:
switch (c) {
case '\0':
spectype = 3;
state = -1;
break;
case '2':
state = 8;
break;
case '3':
state = 9;
break;
default:
goto tabspecerr;
}
break;
case 8:
if (c == '\0') {
spectype = 4;
state = -1;
}
else
goto tabspecerr;
break;
case 9:
if (c == '\0') {
spectype = 5;
state = -1;
}
else
goto tabspecerr;
break;
case 10:
if (c == '\0') {
spectype = 6;
state = -1;
}
else
goto tabspecerr;
break;
case 11:
if (c == '\0') {
spectype = 7;
state = -1;
}
else
goto tabspecerr;
break;
case 12:
if (c == '\0') {
spectype = 8;
state = -1;
}
else
goto tabspecerr;
break;
case 13:
if (c == '\0') {
spectype = 9;
state = -1;
}
else
goto tabspecerr;
break;
case 14:
if (type(c) == NUMBER) {
state = 14;
number[0] = number[0] * 10 + c - '0';
}
else if (c == '\0') {
spectype = 10;
state = -1;
}
else
goto tabspecerr;
break;
}
}
if (spectype <= 9) return(spectype);
if (spectype == 10) {
spectype = nextspec++;
spectbl[spectype] = nexttab;
*nexttab = 1;
if(number[0] == 0)number[0] = 1; /* Prevent infinite loop. */
while (*nexttab < LINELEN) {
*(nexttab + 1) = *nexttab;
*++nexttab += number[0];
}
*nexttab++ = '\0';
return(spectype);
}
if (spectype == 11) {
spectype = nextspec++;
spectbl[spectype] = nexttab;
*nexttab++ = 1;
for (ix = 0; ix <= tp; ix++) {
*nexttab++ = number[ix];
if ((number[ix] >= number[ix+1]) && (ix != tp))
goto tabspecerr;
}
*nexttab++ = '\0';
return(spectype);
}
if (lock == 1) {
fprintf(stderr,"newform: tabspec indirection illegal\n");
exit(1);
}
lock = 1;
if (spectype == 12) {
if (sitabspec >= 0) {
tspec = sitabspec;
}
else {
if ( (stptr=readline(stdin,siline)) != NULL){
kludge = 1;
tspec = readspec(siline);
sitabspec = tspec;
}
}
}
if (spectype == 13) {
if ((fp = fopen(filep,"r")) == NULL) {
fprintf(stderr,"newform: can't open %s\n", filep);
exit(1);
}
readline(fp,work);
fclose(fp);
tspec = readspec(work);
}
lock = 0;
return(tspec);
tabspecerr:
fprintf(stderr,"newform: tabspec in error\n");
fprintf(stderr,"tabspec is \t-a\t-a2\t-c\t-c2\t-c3\t-f\t-p\t-s\n");
fprintf(stderr,"\t\t-u\t--\t--file\t-number\tnumber,..,number\n");
exit(1);
return(-1); /* Stops 'lint's complaint about return(e) VS return. */
}
int readspec(p) /* Read a tabspec from a file */
register char *p; /* Pointer to buffer to process */
{
int state, /* Current state */
firsttime, /* Flag to indicate spec found */
value; /* Function value */
char c, /* Char being looked at */
*tabspecp, /* Pointer to spec string */
*restore = " ", /* Character to be restored */
repch; /* Character to replace with */
state = 0;
firsttime = 1;
while (state >= 0) {
c = *p++;
switch (state) {
case 0:
state = (c == '<') ? 1 : 0;
break;
case 1:
state = (c == ':') ? 2 : 0;
break;
case 2:
state = (c == 't') ? 4
: ((c == ' ') || (c == '\t')) ? 2 : 3;
break;
case 3:
state = ((c == ' ') || (c == '\t')) ? 2 : 3;
break;
case 4:
if (firsttime) {
tabspecp = --p;
p++;
firsttime = 0;
}
if ((c == ' ') || (c == '\t') || (c == ':')) {
repch = *(restore = p - 1);
*restore = '\0';
}
state = (c == ':') ? 6
: ((c == ' ') || (c == '\t')) ? 5 : 4;
break;
case 5:
state = (c == ':') ? 6 : 5;
break;
case 6:
state = (c == '>') ? -2 : 5;
break;
}
if (c == '\n') state = -1;
}
if (okludge) strcpy(format,tabspecp);
value = (state == -1) ? 0 : cnvtspec(tabspecp);
*restore = repch;
return(value);
}
char *readline(fp,area) /* Read one line from the file. */
FILE *fp; /* File to read from */
char *area; /* Array of characters to read into */
{
int c; /* Current character */
char *xarea, /* Temporary pointer to character array */
UNDEF = '\377', /* Undefined char for return */
*temp; /* Array pointer */
/* check for existence of stdin before attempting to read */
/* kludge refers to reading from stdin to get tabspecs for option -i-- */
xarea = area;
if (kludge && (fp == stdin)) {
if (fp != NULL) {
temp = siline;
while ((*area++ = *temp++) != '\n') ;
kludge = 0;
return(xarea);
}
else
return(NULL);
}
else {
/* check for exceeding size of buffer when reading valid input */
while ( wlast - area ) {
switch(c = getc(fp)){
case EOF:
if (area == xarea)
return(NULL);
case '\n': /*EOF falls through to here*/
*area = '\n';
return(xarea);
}
*area=c;
*area++;
}
printf("newform: input line larger than buffer area \n");
exit(1);
}
return(&UNDEF); /* Stops 'lint's complaint about return(e) VS return. */
}
/* _________________________________________________________________ */
char type(c) /* Determine type of a character */
char c; /* Character to check */
{
return((c >= '0') && (c <= '9') ? NUMBER : c);
}
process(fp) /* Process one line of input */
FILE *fp; /* File pointer for current input */
{
struct f *lp; /* Pointer to structs */
char *readline(); /* Function */
char chrnow; /* For int to char conversion. */
while (readline(fp,&work[NCOLS]) != NULL) {
effll = 80;
pachar = ' ';
pfirst = plast = &work[NCOLS];
while (*plast != '\n') plast++;
/* changes to line parsing includes checks for exceeding */
/* line size when modifying text */
for (lp = optl ; lp < flp ; lp++) {
switch (lp->option) {
case 'a':
append(lp->param);
break;
case 'b':
if (lp->param <= (plast - pfirst))
begtrunc(lp->param);
else
fprintf(stderr,"newform: truncate request larger than line, %d \n", (plast - pfirst));
break;
case 'c':
chrnow = lp->param;
pachar = chrnow ? chrnow : ' ';
break;
case 'e':
if (lp->param <= (plast - pfirst))
endtrunc(lp->param);
else
fprintf(stderr,"newform: truncate request larger than line, %d \n", (plast - pfirst));
break;
case 'f':
/* Ignored */
break;
case 'i':
inputtabs(lp->param);
break;
case 'l': /* New eff line length */
effll = lp->param ? lp->param : 72;
break;
case 's':
sstrip();
break;
case 'o':
outputtabs(lp->param);
break;
case 'p':
prepend(lp->param);
break;
}
}
if(soption)sadd();
*++plast = '\0';
fputs(pfirst,stdout);
}
}
append(n) /* Append characters to end of line. */
int n; /* Number of characters to append. */
{
if (plast - pfirst < effll) {
n = n ? n : effll - (plast - pfirst);
if (plast + n > wlast) center();
while (n--) *plast++ = pachar;
*plast = '\n';
}
}
/* _________________________________________________________________ */
prepend(n) /* Prepend characters to line. */
int n; /* Number of characters to prepend. */
{
if (plast - pfirst < effll) {
n = n ? n : effll - (plast - pfirst);
if (pfirst - n < wfirst) center();
while (n--) *--pfirst = pachar;
}
}
/* _________________________________________________________________ */
begtrunc(n) /* Truncate characters from beginning of line. */
int n; /* Number of characters to truncate. */
{
if (plast - pfirst > effll) {
n = n ? n : plast - pfirst - effll;
pfirst += n;
if (pfirst >= plast)
*(pfirst = plast = &work[NCOLS]) = '\n';
}
}
/* _________________________________________________________________ */
endtrunc(n) /* Truncate characters from end of line.*/
int n; /* Number of characters to truncate. */
{
if (plast - pfirst > effll) {
n = n ? n : plast - pfirst - effll;
plast -= n;
if (pfirst >= plast)
*(pfirst = plast = &work[NCOLS]) = '\n';
else
*plast = '\n';
}
}
inputtabs(p) /* Expand according to input tab specifications.*/
int p; /* Pointer to tab specification. */
{
int *tabs; /* Pointer to tabs */
char *tfirst, /* Pointer to new buffer start */
*tlast; /* Pointer to new buffer end */
register char c; /* Character being scanned */
int logcol; /* Logical column */
tabs = spectbl[p];
tfirst = tlast = work;
logcol = 1;
center();
while (pfirst <= plast) {
if (logcol >= *tabs) tabs++;
switch (c = *pfirst++) {
case '\b':
if (logcol > 1) logcol--;
*tlast++ = c;
if (logcol < *tabs) tabs--;
break;
case '\t':
while (logcol < *tabs) {
*tlast++ = ' ';
logcol++;
}
tabs++;
break;
default:
*tlast++ = c;
logcol++;
break;
}
}
pfirst = tfirst;
plast = --tlast;
}
/* Add SCCS SID (generated by a "get -m" command) to the end of each line.
Sequence is as follows for EACH line:
Check for at least 1 tab. Err if none.
Strip off all char up to & including first tab.
If more than 8 char were stripped, the 8 th is replaced by
a '*' & the remainder are discarded.
Unless user specified an "a", append blanks to fill
out line to eff. line length (default= 72 char).
Truncate lines > eff. line length (default=72).
Add stripped char to end of line. */
sstrip()
{
register int i, k;
char *c,*savec;
k = -1;
c = pfirst;
while(*c != '\t' && *c != '\n'){k++; c++;}
if(*c != '\t'){fprintf(stderr,"not -s format\r\n"); exit(1);}
savec = c;
c = pfirst;
savek = (k > 7) ? 7 : k;
for(i=0; i <= savek; i++)savchr[i] = *c++; /* Tab not saved */
if(k > 7)savchr[7] = '*';
pfirst = ++savec; /* Point pfirst to char after tab */
}
/* ================================================================= */
sadd()
{
register int i;
for(i=0; i <= savek; i++)*plast++ = savchr[i];
*plast = '\n';
}
outputtabs(p) /* Contract according to output tab specifications. */
int p; /* Pointer to tab specification. */
{
int *tabs; /* Pointer to tabs */
char *tfirst, /* Pointer to new buffer start */
*tlast, /* Pointer to new buffer end */
*mark; /* Marker pointer */
register char c; /* Character being scanned */
int logcol; /* Logical column */
tabs = spectbl[p];
tfirst = tlast = pfirst;
logcol = 1;
while (pfirst <= plast) {
if (logcol == *tabs) tabs++;
switch (c = *pfirst++) {
case '\b':
if (logcol > 1) logcol--;
*tlast++ = c;
if (logcol < *tabs) tabs--;
break;
case ' ':
mark = tlast;
do {
*tlast++ = ' ';
logcol++;
if (logcol == *tabs) {
*mark++ = '\t';
tlast = mark;
tabs++;
}
} while (*pfirst++ == ' ');
pfirst--;
break;
default:
logcol++;
*tlast++ = c;
break;
}
}
pfirst = tfirst;
plast = --tlast;
}