1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * FUNCTION PAGE INDEX
32 * Function Page Description
33 * append 16 Append chars to end of line.
34 * begtrunc 16 Truncate characters from beginning of line.
35 * center 5 Center text in the work area.
36 * cnvtspec 7 Convert tab spec to tab positions.
37 * endtrunc 16 Truncate chars from end of line.
38 * inputtabs 17 Expand according to input tab specs.
39 * main 3 MAIN
40 * inputn 5 Read a command line option number.
41 * options 4 Process command line options.
42 * outputtabs 19 Contract according to output tab specs.
43 * prepend 16 Prepend chars to line.
44 * process 15 Process one line of input.
45 * readline 14 Read one line from the file.
46 * readspec 12 Read a tabspec from a file.
47 * sstrip 18 Strip SCCS SID char from beginning of line.
48 * sadd 18 Add SCCS SID chars to end of line.
49 * type 14 Determine type of a character.
50 */
51
52 #include <stdlib.h>
53 #include <string.h>
54 #include <stdio.h>
55
56 #define MAXOPTS 50
57 #define NCOLS 512
58 #define MAXLINE 512
59 #define NUMBER '0'
60 #define LINELEN 80
61
62 static int tabtbl[500] = { /* Table containing tab stops */
63 1, 9, 17, 25, 33, 41, 49, 57, 65, 73, 0,
64 /* Default tabs */
65 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */
66 1, 10, 16, 40, 72, 0, /* IBM 370 Assembler (alt.) */
67 1, 8, 12, 16, 20, 55, 0, /* COBOL */
68 1, 6, 10, 14, 49, 0, /* COBOL (crunched) */
69 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67, 0,
70 /* COBOL (crunched, many cols.) */
71 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */
72 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
73 /* PL/1 */
74 1, 10, 55, 0, /* SNOBOL */
75 1, 12, 20, 44, 0 }, /* UNIVAC Assembler */
76
77 *nexttab = &tabtbl[87], /* Pointer to next empty slot */
78
79 *spectbl[40] = { /* Table of pointers into tabtbl */
80 &tabtbl[0], /* Default specification */
81 &tabtbl[11], /* -a specification */
82 &tabtbl[17], /* -a2 specification */
83 &tabtbl[23], /* -c specification */
84 &tabtbl[30], /* -c2 specification */
85 &tabtbl[36], /* -c3 specification */
86 &tabtbl[54], /* -f specification */
87 &tabtbl[61], /* -p specification */
88 &tabtbl[78], /* -s specification */
89 &tabtbl[82] }, /* -u specification */
90
91 savek; /* Stores char count stripped from front of line. */
92 static int nextspec = 10, /* Index to next slot */
93 sitabspec = -1, /* Index to "standard input" spec. */
94 effll = 80, /* Effective line length */
95 optionf = 0, /* 'f' option set */
96 soption = 0, /* 's' option used. */
97 files = 0, /* Number of input files */
98 kludge = 0, /* Kludge to allow reread of 1st line */
99 okludge = 0, /* Kludge to indicate reading "o" option */
100 lock = 0; /* Lock to prevent file indirection */
101
102 static char pachar = ' ', /* Prepend/append character */
103 work[3*NCOLS+1], /* Work area */
104 *pfirst, /* Pointer to beginning of line */
105 *plast, /* Pointer to end of line */
106 *wfirst = &work[0], /* Pointer to beginning of work area */
107 *wlast = &work[3*NCOLS], /* Pointer to end of work area */
108 siline[NCOLS], /* First standard input line */
109 savchr[8], /* Holds char stripped from line start */
110 format[80] = "-8"; /* Array to hold format line */
111
112 static struct f {
113 char option;
114 int param;
115 } optl[MAXOPTS], /* List of command line options */
116 *flp = optl; /* Pointer to next open slot */
117
118 static void append(int);
119 static void begtrunc(int);
120 static void center(void);
121 static int cnvtspec(char *);
122 static void endtrunc(int);
123 static int inputn(char *);
124 static void inputtabs(int);
125 static void options(int, char **);
126 static void outputtabs(int);
127 static void prepend(int);
128 static void process(FILE *);
129 static char *readline(FILE *, char *);
130 static int readspec(char *);
131 static void sadd(void);
132 static void sstrip(void);
133 static char type(char);
134
135 int
main(int argc,char ** argv)136 main(int argc, char **argv)
137 {
138 char *scan; /* String scan pointer */
139 FILE *fp; /* Pointer to current file */
140
141 options(argc, argv);
142 if (optionf) { /* Write tab spec format line. */
143 (void) fputs("<:t", stdout);
144 (void) fputs(format, stdout);
145 (void) fputs(" d:>\n", stdout);
146 }
147 if (files) {
148 while (--argc) {
149 scan = *++argv;
150 if (*scan != '-') {
151 if ((fp = fopen(scan, "r")) == NULL) {
152 (void) fprintf(stderr,
153 "newform: can't open %s\n", scan);
154 exit(1);
155 }
156 process(fp);
157 (void) fclose(fp);
158 }
159 }
160 } else {
161 process(stdin);
162 }
163 return (0);
164 }
165
166
167 static void
options(int argc,char ** argv)168 options(int argc, char **argv) /* Process command line options */
169 {
170 int n; /* Temporary number holder */
171 char *scan; /* Pointer to individual option strings */
172 char c; /* Option character */
173
174 /* changes to option parsing includes checks for exceeding */
175 /* initial buffer sizes */
176
177 while (--argc > 0) {
178 scan = *++argv;
179 if (*scan++ == '-') {
180 switch (c = *scan++) {
181 case 'a':
182 flp->option = 'a';
183 flp->param = inputn(scan);
184 if (flp->param <= NCOLS)
185 flp++;
186 else {
187 (void) fprintf(stderr, "newform: "
188 "prefix request larger than "
189 "buffer, %d\n", NCOLS);
190 exit(1);
191 }
192 break;
193 case 'b':
194 case 'e':
195 flp->option = c;
196 flp->param = inputn(scan);
197 flp++;
198 break;
199 case 'p':
200 flp->option = 'p';
201 flp->param = inputn(scan);
202 if (flp->param <= NCOLS)
203 flp++;
204 else {
205 (void) fprintf(stderr, "newform: "
206 "prefix request larger than "
207 "buffer, %d\n", NCOLS);
208 exit(1);
209 }
210 break;
211 case 'c':
212 flp->option = 'c';
213 flp->param = *scan ? *scan : ' ';
214 flp++;
215 break;
216 case 'f':
217 flp->option = 'f';
218 optionf++;
219 flp++;
220 break;
221 case 'i':
222 flp->option = 'i';
223 flp->param = cnvtspec(scan);
224 flp++;
225 break;
226 case 'o':
227 if (*scan == '-' && *(scan+1) == '0' &&
228 *(scan+2) == '\0')
229 break;
230 /* Above allows the -o-0 option to be ignored. */
231 flp->option = 'o';
232 (void) strcpy(format, scan);
233 okludge++;
234 flp->param = cnvtspec(scan);
235 okludge--;
236 if (flp->param == 0)
237 (void) strcpy(format, "-8");
238 flp++;
239 break;
240 case 'l':
241 flp->option = 'l';
242 flp->param = ((n = inputn(scan)) ? n : 72);
243 if (flp->param <= (3*NCOLS))
244 flp++;
245 else {
246 (void) fprintf(stderr, "newform: "
247 "line length request larger "
248 "than buffer, %d \n", (3*NCOLS));
249 exit(1);
250 }
251 break;
252 case 's':
253 flp->option = 's';
254 flp++;
255 soption++;
256 break;
257 default:
258 goto usageerr;
259 }
260 }
261 else
262 files++;
263 }
264 return;
265 usageerr:
266 (void) fprintf(stderr, "usage: newform [-s] [-itabspec] [-otabspec] ");
267 (void) fprintf(stderr, "[-pn] [-en] [-an] [-f] [-cchar]\n\t\t");
268 (void) fprintf(stderr, "[-ln] [-bn] [file ...]\n");
269 exit(1);
270 }
271 /* _________________________________________________________________ */
272
273 static int
inputn(char * scan)274 inputn(char *scan) /* Read a command option number */
275 /* Pointer to string of digits */
276 {
277 int n; /* Number */
278 char c; /* Character being scanned */
279
280 n = 0;
281 while ((c = *scan++) >= '0' && c <= '9')
282 n = n * 10 + c - '0';
283 return (n);
284 }
285 /* _________________________________________________________________ */
286
287 static void
center(void)288 center(void) /* Center the text in the work area. */
289 {
290 char *tfirst; /* Pointer for moving buffer down */
291 char *tlast; /* Pointer for moving buffer up */
292 char *tptr; /* Temporary */
293
294 if (plast - pfirst > MAXLINE) {
295 (void) fprintf(stderr, "newform: internal line too long\n");
296 exit(1);
297 }
298 if (pfirst < &work[NCOLS]) {
299 tlast = plast + (&work[NCOLS] - pfirst);
300 tptr = tlast;
301 while (plast >= pfirst) *tlast-- = *plast--;
302 pfirst = ++tlast;
303 plast = tptr;
304 } else {
305 tfirst = &work[NCOLS];
306 tptr = tfirst;
307 while (pfirst <= plast) *tfirst++ = *pfirst++;
308 plast = --tfirst;
309 pfirst = tptr;
310 }
311 }
312
313 static int
cnvtspec(char * p)314 cnvtspec(char *p) /* Convert tab specification to tab positions. */
315 /* Pointer to spec string. */
316 {
317 int state, /* DFA state */
318 spectype, /* Specification type */
319 number[40], /* Array of read-in numbers */
320 tp, /* Pointer to last number */
321 ix; /* Temporary */
322 int tspec = 0; /* Tab spec pointer */
323 char c, /* Temporary */
324 *filep; /* Pointer to file name */
325 FILE *fp; /* File pointer */
326
327 state = 0;
328 while (state >= 0) {
329 c = *p++;
330 switch (state) {
331 case 0:
332 switch (type(c)) {
333 case '\0':
334 spectype = 0;
335 state = -1;
336 break;
337 case NUMBER:
338 state = 1;
339 tp = 0;
340 number[tp] = c - '0';
341 break;
342 case '-':
343 state = 3;
344 break;
345 default:
346 goto tabspecerr;
347 }
348 break;
349 case 1:
350 switch (type(c)) {
351 case '\0':
352 spectype = 11;
353 state = -1;
354 break;
355 case NUMBER:
356 state = 1;
357 number[tp] = number[tp] * 10 + c - '0';
358 break;
359 case ',':
360 state = 2;
361 break;
362 default:
363 goto tabspecerr;
364 }
365 break;
366 case 2:
367 if (type(c) == NUMBER) {
368 state = 1;
369 number[++tp] = c - '0';
370 }
371 else
372 goto tabspecerr;
373
374 break;
375 case 3:
376 switch (type(c)) {
377 case '-':
378 state = 4;
379 break;
380 case 'a':
381 state = 5;
382 break;
383 case 'c':
384 state = 7;
385 break;
386 case 'f':
387 state = 10;
388 break;
389 case 'p':
390 state = 11;
391 break;
392 case 's':
393 state = 12;
394 break;
395 case 'u':
396 state = 13;
397 break;
398 case NUMBER:
399 state = 14;
400 number[0] = c - '0';
401 break;
402 default:
403 goto tabspecerr;
404 }
405 break;
406 case 4:
407 if (c == '\0') {
408 spectype = 12;
409 state = -1;
410 } else {
411 filep = --p;
412 spectype = 13;
413 state = -1;
414 }
415 break;
416 case 5:
417 if (c == '\0') {
418 spectype = 1;
419 state = -1;
420 } else if (c == '2')
421 state = 6;
422 else
423 goto tabspecerr;
424 break;
425 case 6:
426 if (c == '\0') {
427 spectype = 2;
428 state = -1;
429 }
430 else
431 goto tabspecerr;
432 break;
433 case 7:
434 switch (c) {
435 case '\0':
436 spectype = 3;
437 state = -1;
438 break;
439 case '2':
440 state = 8;
441 break;
442 case '3':
443 state = 9;
444 break;
445 default:
446 goto tabspecerr;
447 }
448 break;
449 case 8:
450 if (c == '\0') {
451 spectype = 4;
452 state = -1;
453 }
454 else
455 goto tabspecerr;
456 break;
457 case 9:
458 if (c == '\0') {
459 spectype = 5;
460 state = -1;
461 }
462 else
463 goto tabspecerr;
464 break;
465 case 10:
466 if (c == '\0') {
467 spectype = 6;
468 state = -1;
469 }
470 else
471 goto tabspecerr;
472 break;
473 case 11:
474 if (c == '\0') {
475 spectype = 7;
476 state = -1;
477 }
478 else
479 goto tabspecerr;
480 break;
481 case 12:
482 if (c == '\0') {
483 spectype = 8;
484 state = -1;
485 }
486 else
487 goto tabspecerr;
488 break;
489 case 13:
490 if (c == '\0') {
491 spectype = 9;
492 state = -1;
493 }
494 else
495 goto tabspecerr;
496 break;
497 case 14:
498 if (type(c) == NUMBER) {
499 state = 14;
500 number[0] = number[0] * 10 + c - '0';
501 } else if (c == '\0') {
502 spectype = 10;
503 state = -1;
504 } else
505 goto tabspecerr;
506 break;
507 }
508 }
509 if (spectype <= 9)
510 return (spectype);
511 if (spectype == 10) {
512 spectype = nextspec++;
513 spectbl[spectype] = nexttab;
514 *nexttab = 1;
515 if (number[0] == 0) number[0] = 1; /* Prevent infinite loop. */
516 while (*nexttab < LINELEN) {
517 *(nexttab + 1) = *nexttab;
518 *++nexttab += number[0];
519 }
520 *nexttab++ = '\0';
521 return (spectype);
522 }
523 if (spectype == 11) {
524 spectype = nextspec++;
525 spectbl[spectype] = nexttab;
526 *nexttab++ = 1;
527 for (ix = 0; ix <= tp; ix++) {
528 *nexttab++ = number[ix];
529 if ((number[ix] >= number[ix+1]) && (ix != tp))
530 goto tabspecerr;
531 }
532 *nexttab++ = '\0';
533 return (spectype);
534 }
535 if (lock == 1) {
536 (void) fprintf(stderr,
537 "newform: tabspec indirection illegal\n");
538 exit(1);
539 }
540 lock = 1;
541 if (spectype == 12) {
542 if (sitabspec >= 0) {
543 tspec = sitabspec;
544 } else {
545 if (readline(stdin, siline) != NULL) {
546 kludge = 1;
547 tspec = readspec(siline);
548 sitabspec = tspec;
549 }
550 }
551 }
552 if (spectype == 13) {
553 if ((fp = fopen(filep, "r")) == NULL) {
554 (void) fprintf(stderr,
555 "newform: can't open %s\n", filep);
556 exit(1);
557 }
558 (void) readline(fp, work);
559 (void) fclose(fp);
560 tspec = readspec(work);
561 }
562 lock = 0;
563 return (tspec);
564 tabspecerr:
565 (void) fprintf(stderr, "newform: tabspec in error\n");
566 (void) fprintf(stderr,
567 "tabspec is \t-a\t-a2\t-c\t-c2\t-c3\t-f\t-p\t-s\n");
568 (void) fprintf(stderr,
569 "\t\t-u\t--\t--file\t-number\tnumber,..,number\n");
570 exit(1);
571 /* NOTREACHED */
572 }
573
574 static int
readspec(char * p)575 readspec(char *p) /* Read a tabspec from a file */
576 /* Pointer to buffer to process */
577 {
578 int state, /* Current state */
579 firsttime, /* Flag to indicate spec found */
580 value; /* Function value */
581 char c, /* Char being looked at */
582 *tabspecp, /* Pointer to spec string */
583 *restore = " ", /* Character to be restored */
584 repch; /* Character to replace with */
585
586 state = 0;
587 firsttime = 1;
588 while (state >= 0) {
589 c = *p++;
590 switch (state) {
591 case 0:
592 state = (c == '<') ? 1 : 0;
593 break;
594 case 1:
595 state = (c == ':') ? 2 : 0;
596 break;
597 case 2:
598 state = (c == 't') ? 4
599 : ((c == ' ') || (c == '\t')) ? 2 : 3;
600 break;
601 case 3:
602 state = ((c == ' ') || (c == '\t')) ? 2 : 3;
603 break;
604 case 4:
605 if (firsttime) {
606 tabspecp = --p;
607 p++;
608 firsttime = 0;
609 }
610 if ((c == ' ') || (c == '\t') || (c == ':')) {
611 repch = *(restore = p - 1);
612 *restore = '\0';
613 }
614 state = (c == ':') ? 6
615 : ((c == ' ') || (c == '\t')) ? 5 : 4;
616 break;
617 case 5:
618 state = (c == ':') ? 6 : 5;
619 break;
620 case 6:
621 state = (c == '>') ? -2 : 5;
622 break;
623 }
624 if (c == '\n') state = -1;
625 }
626 if (okludge)
627 (void) strcpy(format, tabspecp);
628 value = (state == -1) ? 0 : cnvtspec(tabspecp);
629 *restore = repch;
630 return (value);
631 }
632
633 static char *
readline(FILE * fp,char * area)634 readline(FILE *fp, char *area) /* Read one line from the file. */
635 /* fp - File to read from */
636 /* area - Array of characters to read into */
637 {
638 int c; /* Current character */
639 char *xarea, /* Temporary pointer to character array */
640 *temp; /* Array pointer */
641
642
643
644 /* check for existence of stdin before attempting to read */
645 /* kludge refers to reading from stdin to get tabspecs for option -i-- */
646
647 xarea = area;
648 if (kludge && (fp == stdin)) {
649 if (fp != NULL) {
650 temp = siline;
651 while ((*area++ = *temp++) != '\n')
652 ;
653 kludge = 0;
654 return (xarea);
655 } else
656 return (NULL);
657 } else {
658
659 /* check for exceeding size of buffer when reading valid input */
660
661 while (wlast - area) {
662 switch (c = getc(fp)) {
663 case EOF:
664 if (area == xarea)
665 return (NULL);
666 /* FALLTHROUGH */
667 case '\n': /* EOF falls through to here */
668 *area = '\n';
669 return (xarea);
670 }
671 *area = c;
672 area++;
673 }
674 (void) printf("newform: input line larger than buffer area \n");
675 exit(1);
676 }
677 /* NOTREACHED */
678 }
679 /* _________________________________________________________________ */
680
681 static char
type(char c)682 type(char c) /* Determine type of a character */
683 /* Character to check */
684 {
685 return ((c >= '0') && (c <= '9') ? NUMBER : c);
686 }
687
688 static void
process(FILE * fp)689 process(FILE *fp) /* Process one line of input */
690 /* File pointer for current input */
691 {
692 struct f *lp; /* Pointer to structs */
693 char chrnow; /* For int to char conversion. */
694
695 while (readline(fp, &work[NCOLS]) != NULL) {
696 effll = 80;
697 pachar = ' ';
698 pfirst = plast = &work[NCOLS];
699 while (*plast != '\n') plast++;
700
701 /* changes to line parsing includes checks for exceeding */
702 /* line size when modifying text */
703
704 for (lp = optl; lp < flp; lp++) {
705 switch (lp->option) {
706 case 'a':
707 append(lp->param);
708 break;
709 case 'b':
710 if (lp->param <= (plast - pfirst))
711 begtrunc(lp->param);
712 else
713 (void) fprintf(stderr,
714 "newform: truncate "
715 "request larger than line, %d \n",
716 (plast - pfirst));
717 break;
718 case 'c':
719 chrnow = lp->param;
720 pachar = chrnow ? chrnow : ' ';
721 break;
722 case 'e':
723 if (lp->param <= (plast - pfirst))
724 endtrunc(lp->param);
725 else
726 (void) fprintf(stderr,
727 "newform: truncate "
728 "request larger than line, %d \n",
729 (plast - pfirst));
730 break;
731 case 'f':
732 /* Ignored */
733 break;
734 case 'i':
735 inputtabs(lp->param);
736 break;
737 case 'l': /* New eff line length */
738 effll = lp->param ? lp->param : 72;
739 break;
740 case 's':
741 sstrip();
742 break;
743 case 'o':
744 outputtabs(lp->param);
745 break;
746 case 'p':
747 prepend(lp->param);
748 break;
749 }
750 }
751 if (soption) sadd();
752 *++plast = '\0';
753 (void) fputs(pfirst, stdout);
754 }
755 }
756
757 static void
append(int n)758 append(int n) /* Append characters to end of line. */
759 /* Number of characters to append. */
760 {
761 if (plast - pfirst < effll) {
762 n = n ? n : effll - (plast - pfirst);
763 if (plast + n > wlast) center();
764 while (n--) *plast++ = pachar;
765 *plast = '\n';
766 }
767 }
768 /* _________________________________________________________________ */
769
770 static void
prepend(int n)771 prepend(int n) /* Prepend characters to line. */
772 /* Number of characters to prepend. */
773 {
774 if (plast - pfirst < effll) {
775 n = n ? n : effll - (plast - pfirst);
776 if (pfirst - n < wfirst) center();
777 while (n--) *--pfirst = pachar;
778 }
779 }
780 /* _________________________________________________________________ */
781
782 static void
begtrunc(int n)783 begtrunc(int n) /* Truncate characters from beginning of line. */
784 /* Number of characters to truncate. */
785 {
786 if (plast - pfirst > effll) {
787 n = n ? n : plast - pfirst - effll;
788 pfirst += n;
789 if (pfirst >= plast)
790 *(pfirst = plast = &work[NCOLS]) = '\n';
791 }
792 }
793 /* _________________________________________________________________ */
794
795 static void
endtrunc(int n)796 endtrunc(int n) /* Truncate characters from end of line. */
797 /* Number of characters to truncate. */
798 {
799 if (plast - pfirst > effll) {
800 n = n ? n : plast - pfirst - effll;
801 plast -= n;
802 if (pfirst >= plast)
803 *(pfirst = plast = &work[NCOLS]) = '\n';
804 else
805 *plast = '\n';
806 }
807 }
808
809 static void
inputtabs(int p)810 inputtabs(int p) /* Expand according to input tab specifications. */
811 /* Pointer to tab specification. */
812 {
813 int *tabs; /* Pointer to tabs */
814 char *tfirst, /* Pointer to new buffer start */
815 *tlast; /* Pointer to new buffer end */
816 char c; /* Character being scanned */
817 int logcol; /* Logical column */
818
819 tabs = spectbl[p];
820 tfirst = tlast = work;
821 logcol = 1;
822 center();
823 while (pfirst <= plast) {
824 if (logcol >= *tabs) tabs++;
825 switch (c = *pfirst++) {
826 case '\b':
827 if (logcol > 1) logcol--;
828 *tlast++ = c;
829 if (logcol < *tabs) tabs--;
830 break;
831 case '\t':
832 while (logcol < *tabs) {
833 *tlast++ = ' ';
834 logcol++;
835 }
836 tabs++;
837 break;
838 default:
839 *tlast++ = c;
840 logcol++;
841 break;
842 }
843 }
844 pfirst = tfirst;
845 plast = --tlast;
846 }
847 /*
848 * Add SCCS SID (generated by a "get -m" command) to the end of each line.
849 * Sequence is as follows for EACH line:
850 * Check for at least 1 tab. Err if none.
851 * Strip off all char up to & including first tab.
852 * If more than 8 char were stripped, the 8 th is replaced by
853 * a '*' & the remainder are discarded.
854 * Unless user specified an "a", append blanks to fill
855 * out line to eff. line length (default= 72 char).
856 * Truncate lines > eff. line length (default=72).
857 * Add stripped char to end of line.
858 */
859 static void
sstrip(void)860 sstrip(void)
861 {
862 int i, k;
863 char *c, *savec;
864
865 k = -1;
866 c = pfirst;
867 while (*c != '\t' && *c != '\n') {
868 k++;
869 c++;
870 }
871 if (*c != '\t') {
872 (void) fprintf(stderr, "not -s format\r\n");
873 exit(1);
874 }
875
876 savec = c;
877 c = pfirst;
878 savek = (k > 7) ? 7 : k;
879 for (i = 0; i <= savek; i++) savchr[i] = *c++; /* Tab not saved */
880 if (k > 7) savchr[7] = '*';
881
882 pfirst = ++savec; /* Point pfirst to char after tab */
883 }
884 /* ================================================================= */
885
886 static void
sadd(void)887 sadd(void)
888 {
889 int i;
890
891 for (i = 0; i <= savek; i++) *plast++ = savchr[i];
892 *plast = '\n';
893 }
894
895 static void
outputtabs(int p)896 outputtabs(int p) /* Contract according to output tab specifications. */
897 /* Pointer to tab specification. */
898 {
899 int *tabs; /* Pointer to tabs */
900 char *tfirst, /* Pointer to new buffer start */
901 *tlast, /* Pointer to new buffer end */
902 *mark; /* Marker pointer */
903 char c; /* Character being scanned */
904 int logcol; /* Logical column */
905
906 tabs = spectbl[p];
907 tfirst = tlast = pfirst;
908 logcol = 1;
909 while (pfirst <= plast) {
910 if (logcol == *tabs) tabs++;
911 switch (c = *pfirst++) {
912 case '\b':
913 if (logcol > 1) logcol--;
914 *tlast++ = c;
915 if (logcol < *tabs) tabs--;
916 break;
917 case ' ':
918 mark = tlast;
919 do {
920 *tlast++ = ' ';
921 logcol++;
922 if (logcol == *tabs) {
923 *mark++ = '\t';
924 tlast = mark;
925 tabs++;
926 }
927 } while (*pfirst++ == ' ');
928 pfirst--;
929 break;
930 default:
931 logcol++;
932 *tlast++ = c;
933 break;
934 }
935 }
936 pfirst = tfirst;
937 plast = --tlast;
938 }
939