#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAXOPTS 50
#define NCOLS 512
#define MAXLINE 512
#define NUMBER '0'
#define LINELEN 80
static int tabtbl[500] = {
1, 9, 17, 25, 33, 41, 49, 57, 65, 73, 0,
1, 10, 16, 36, 72, 0,
1, 10, 16, 40, 72, 0,
1, 8, 12, 16, 20, 55, 0,
1, 6, 10, 14, 49, 0,
1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67, 0,
1, 7, 11, 15, 19, 23, 0,
1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
1, 10, 55, 0,
1, 12, 20, 44, 0 },
*nexttab = &tabtbl[87],
*spectbl[40] = {
&tabtbl[0],
&tabtbl[11],
&tabtbl[17],
&tabtbl[23],
&tabtbl[30],
&tabtbl[36],
&tabtbl[54],
&tabtbl[61],
&tabtbl[78],
&tabtbl[82] },
savek;
static int nextspec = 10,
sitabspec = -1,
effll = 80,
optionf = 0,
soption = 0,
files = 0,
kludge = 0,
okludge = 0,
lock = 0;
static char pachar = ' ',
work[3*NCOLS+1],
*pfirst,
*plast,
*wfirst = &work[0],
*wlast = &work[3*NCOLS],
siline[NCOLS],
savchr[8],
format[80] = "-8";
static struct f {
char option;
int param;
} optl[MAXOPTS],
*flp = optl;
static void append(int);
static void begtrunc(int);
static void center(void);
static int cnvtspec(char *);
static void endtrunc(int);
static int inputn(char *);
static void inputtabs(int);
static void options(int, char **);
static void outputtabs(int);
static void prepend(int);
static void process(FILE *);
static char *readline(FILE *, char *);
static int readspec(char *);
static void sadd(void);
static void sstrip(void);
static char type(char);
int
main(int argc, char **argv)
{
char *scan;
FILE *fp;
options(argc, argv);
if (optionf) {
(void) fputs("<:t", stdout);
(void) fputs(format, stdout);
(void) fputs(" d:>\n", stdout);
}
if (files) {
while (--argc) {
scan = *++argv;
if (*scan != '-') {
if ((fp = fopen(scan, "r")) == NULL) {
(void) fprintf(stderr,
"newform: can't open %s\n", scan);
exit(1);
}
process(fp);
(void) fclose(fp);
}
}
} else {
process(stdin);
}
return (0);
}
static void
options(int argc, char **argv)
{
int n;
char *scan;
char c;
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 {
(void) 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 {
(void) 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;
flp->option = 'o';
(void) strcpy(format, scan);
okludge++;
flp->param = cnvtspec(scan);
okludge--;
if (flp->param == 0)
(void) strcpy(format, "-8");
flp++;
break;
case 'l':
flp->option = 'l';
flp->param = ((n = inputn(scan)) ? n : 72);
if (flp->param <= (3*NCOLS))
flp++;
else {
(void) 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:
(void) fprintf(stderr, "usage: newform [-s] [-itabspec] [-otabspec] ");
(void) fprintf(stderr, "[-pn] [-en] [-an] [-f] [-cchar]\n\t\t");
(void) fprintf(stderr, "[-ln] [-bn] [file ...]\n");
exit(1);
}
static int
inputn(char *scan)
{
int n;
char c;
n = 0;
while ((c = *scan++) >= '0' && c <= '9')
n = n * 10 + c - '0';
return (n);
}
static void
center(void)
{
char *tfirst;
char *tlast;
char *tptr;
if (plast - pfirst > MAXLINE) {
(void) 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;
}
}
static int
cnvtspec(char *p)
{
int state,
spectype,
number[40],
tp,
ix;
int tspec = 0;
char c,
*filep;
FILE *fp;
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;
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) {
(void) fprintf(stderr,
"newform: tabspec indirection illegal\n");
exit(1);
}
lock = 1;
if (spectype == 12) {
if (sitabspec >= 0) {
tspec = sitabspec;
} else {
if (readline(stdin, siline) != NULL) {
kludge = 1;
tspec = readspec(siline);
sitabspec = tspec;
}
}
}
if (spectype == 13) {
if ((fp = fopen(filep, "r")) == NULL) {
(void) fprintf(stderr,
"newform: can't open %s\n", filep);
exit(1);
}
(void) readline(fp, work);
(void) fclose(fp);
tspec = readspec(work);
}
lock = 0;
return (tspec);
tabspecerr:
(void) fprintf(stderr, "newform: tabspec in error\n");
(void) fprintf(stderr,
"tabspec is \t-a\t-a2\t-c\t-c2\t-c3\t-f\t-p\t-s\n");
(void) fprintf(stderr,
"\t\t-u\t--\t--file\t-number\tnumber,..,number\n");
exit(1);
}
static int
readspec(char *p)
{
int state,
firsttime,
value;
char c,
*tabspecp,
*restore = " ",
repch;
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)
(void) strcpy(format, tabspecp);
value = (state == -1) ? 0 : cnvtspec(tabspecp);
*restore = repch;
return (value);
}
static char *
readline(FILE *fp, char *area)
{
int c;
char *xarea,
*temp;
xarea = area;
if (kludge && (fp == stdin)) {
if (fp != NULL) {
temp = siline;
while ((*area++ = *temp++) != '\n')
;
kludge = 0;
return (xarea);
} else
return (NULL);
} else {
while (wlast - area) {
switch (c = getc(fp)) {
case EOF:
if (area == xarea)
return (NULL);
case '\n':
*area = '\n';
return (xarea);
}
*area = c;
area++;
}
(void) printf("newform: input line larger than buffer area \n");
exit(1);
}
}
static char
type(char c)
{
return ((c >= '0') && (c <= '9') ? NUMBER : c);
}
static void
process(FILE *fp)
{
struct f *lp;
char chrnow;
while (readline(fp, &work[NCOLS]) != NULL) {
effll = 80;
pachar = ' ';
pfirst = plast = &work[NCOLS];
while (*plast != '\n') plast++;
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
(void) 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
(void) fprintf(stderr,
"newform: truncate "
"request larger than line, %d \n",
(plast - pfirst));
break;
case 'f':
break;
case 'i':
inputtabs(lp->param);
break;
case 'l':
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';
(void) fputs(pfirst, stdout);
}
}
static void
append(int n)
{
if (plast - pfirst < effll) {
n = n ? n : effll - (plast - pfirst);
if (plast + n > wlast) center();
while (n--) *plast++ = pachar;
*plast = '\n';
}
}
static void
prepend(int n)
{
if (plast - pfirst < effll) {
n = n ? n : effll - (plast - pfirst);
if (pfirst - n < wfirst) center();
while (n--) *--pfirst = pachar;
}
}
static void
begtrunc(int n)
{
if (plast - pfirst > effll) {
n = n ? n : plast - pfirst - effll;
pfirst += n;
if (pfirst >= plast)
*(pfirst = plast = &work[NCOLS]) = '\n';
}
}
static void
endtrunc(int n)
{
if (plast - pfirst > effll) {
n = n ? n : plast - pfirst - effll;
plast -= n;
if (pfirst >= plast)
*(pfirst = plast = &work[NCOLS]) = '\n';
else
*plast = '\n';
}
}
static void
inputtabs(int p)
{
int *tabs;
char *tfirst,
*tlast;
char c;
int logcol;
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;
}
static void
sstrip(void)
{
int i, k;
char *c, *savec;
k = -1;
c = pfirst;
while (*c != '\t' && *c != '\n') {
k++;
c++;
}
if (*c != '\t') {
(void) 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++;
if (k > 7) savchr[7] = '*';
pfirst = ++savec;
}
static void
sadd(void)
{
int i;
for (i = 0; i <= savek; i++) *plast++ = savchr[i];
*plast = '\n';
}
static void
outputtabs(int p)
{
int *tabs;
char *tfirst,
*tlast,
*mark;
char c;
int logcol;
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;
}