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