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 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 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. 52 */ 53 54 #include <stdlib.h> 55 #include <string.h> 56 #include <stdio.h> 57 58 #define MAXOPTS 50 59 #define NCOLS 512 60 #define MAXLINE 512 61 #define NUMBER '0' 62 #define LINELEN 80 63 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 */ 78 79 *nexttab = &tabtbl[87], /* Pointer to next empty slot */ 80 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 */ 92 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 */ 103 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 */ 113 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 */ 119 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); 136 137 int 138 main(int argc, char **argv) 139 { 140 char *scan; /* String scan pointer */ 141 FILE *fp; /* Pointer to current file */ 142 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); 148 } 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); 157 } 158 process(fp); 159 (void) fclose(fp); 160 } 161 } 162 } else { 163 process(stdin); 164 } 165 return (0); 166 } 167 168 169 static void 170 options(int argc, char **argv) /* Process command line options */ 171 { 172 int n; /* Temporary number holder */ 173 char *scan; /* Pointer to individual option strings */ 174 char c; /* Option character */ 175 176 /* changes to option parsing includes checks for exceeding */ 177 /* initial buffer sizes */ 178 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); 193 } 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); 211 } 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); 252 } 253 break; 254 case 's': 255 flp->option = 's'; 256 flp++; 257 soption++; 258 break; 259 default: 260 goto usageerr; 261 } 262 } 263 else 264 files++; 265 } 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); 272 } 273 /* _________________________________________________________________ */ 274 275 static int 276 inputn(char *scan) /* Read a command option number */ 277 /* Pointer to string of digits */ 278 { 279 int n; /* Number */ 280 char c; /* Character being scanned */ 281 282 n = 0; 283 while ((c = *scan++) >= '0' && c <= '9') 284 n = n * 10 + c - '0'; 285 return (n); 286 } 287 /* _________________________________________________________________ */ 288 289 static void 290 center(void) /* Center the text in the work area. */ 291 { 292 char *tfirst; /* Pointer for moving buffer down */ 293 char *tlast; /* Pointer for moving buffer up */ 294 char *tptr; /* Temporary */ 295 296 if (plast - pfirst > MAXLINE) { 297 (void) fprintf(stderr, "newform: internal line too long\n"); 298 exit(1); 299 } 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; 312 } 313 } 314 315 static int 316 cnvtspec(char *p) /* Convert tab specification to tab positions. */ 317 /* Pointer to spec string. */ 318 { 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 */ 328 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; 349 } 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; 366 } 367 break; 368 case 2: 369 if (type(c) == NUMBER) { 370 state = 1; 371 number[++tp] = c - '0'; 372 } 373 else 374 goto tabspecerr; 375 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; 406 } 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; 416 } 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; 431 } 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; 449 } 450 break; 451 case 8: 452 if (c == '\0') { 453 spectype = 4; 454 state = -1; 455 } 456 else 457 goto tabspecerr; 458 break; 459 case 9: 460 if (c == '\0') { 461 spectype = 5; 462 state = -1; 463 } 464 else 465 goto tabspecerr; 466 break; 467 case 10: 468 if (c == '\0') { 469 spectype = 6; 470 state = -1; 471 } 472 else 473 goto tabspecerr; 474 break; 475 case 11: 476 if (c == '\0') { 477 spectype = 7; 478 state = -1; 479 } 480 else 481 goto tabspecerr; 482 break; 483 case 12: 484 if (c == '\0') { 485 spectype = 8; 486 state = -1; 487 } 488 else 489 goto tabspecerr; 490 break; 491 case 13: 492 if (c == '\0') { 493 spectype = 9; 494 state = -1; 495 } 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; 509 } 510 } 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]; 521 } 522 *nexttab++ = '\0'; 523 return (spectype); 524 } 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; 533 } 534 *nexttab++ = '\0'; 535 return (spectype); 536 } 537 if (lock == 1) { 538 (void) fprintf(stderr, 539 "newform: tabspec indirection illegal\n"); 540 exit(1); 541 } 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; 551 } 552 } 553 } 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); 559 } 560 (void) readline(fp, work); 561 (void) fclose(fp); 562 tspec = readspec(work); 563 } 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 */ 574 } 575 576 static int 577 readspec(char *p) /* Read a tabspec from a file */ 578 /* Pointer to buffer to process */ 579 { 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 */ 587 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; 611 } 612 if ((c == ' ') || (c == '\t') || (c == ':')) { 613 repch = *(restore = p - 1); 614 *restore = '\0'; 615 } 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; 625 } 626 if (c == '\n') state = -1; 627 } 628 if (okludge) 629 (void) strcpy(format, tabspecp); 630 value = (state == -1) ? 0 : cnvtspec(tabspecp); 631 *restore = repch; 632 return (value); 633 } 634 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 */ 639 { 640 int c; /* Current character */ 641 char *xarea, /* Temporary pointer to character array */ 642 *temp; /* Array pointer */ 643 644 645 646 /* check for existence of stdin before attempting to read */ 647 /* kludge refers to reading from stdin to get tabspecs for option -i-- */ 648 649 xarea = area; 650 if (kludge && (fp == stdin)) { 651 if (fp != NULL) { 652 temp = siline; 653 while ((*area++ = *temp++) != '\n') 654 ; 655 kludge = 0; 656 return (xarea); 657 } else 658 return (NULL); 659 } else { 660 661 /* check for exceeding size of buffer when reading valid input */ 662 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); 672 } 673 *area = c; 674 area++; 675 } 676 (void) printf("newform: input line larger than buffer area \n"); 677 exit(1); 678 } 679 /* NOTREACHED */ 680 } 681 /* _________________________________________________________________ */ 682 683 static char 684 type(char c) /* Determine type of a character */ 685 /* Character to check */ 686 { 687 return ((c >= '0') && (c <= '9') ? NUMBER : c); 688 } 689 690 static void 691 process(FILE *fp) /* Process one line of input */ 692 /* File pointer for current input */ 693 { 694 struct f *lp; /* Pointer to structs */ 695 char chrnow; /* For int to char conversion. */ 696 697 while (readline(fp, &work[NCOLS]) != NULL) { 698 effll = 80; 699 pachar = ' '; 700 pfirst = plast = &work[NCOLS]; 701 while (*plast != '\n') plast++; 702 703 /* changes to line parsing includes checks for exceeding */ 704 /* line size when modifying text */ 705 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; 751 } 752 } 753 if (soption) sadd(); 754 *++plast = '\0'; 755 (void) fputs(pfirst, stdout); 756 } 757 } 758 759 static void 760 append(int n) /* Append characters to end of line. */ 761 /* Number of characters to append. */ 762 { 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'; 768 } 769 } 770 /* _________________________________________________________________ */ 771 772 static void 773 prepend(int n) /* Prepend characters to line. */ 774 /* Number of characters to prepend. */ 775 { 776 if (plast - pfirst < effll) { 777 n = n ? n : effll - (plast - pfirst); 778 if (pfirst - n < wfirst) center(); 779 while (n--) *--pfirst = pachar; 780 } 781 } 782 /* _________________________________________________________________ */ 783 784 static void 785 begtrunc(int n) /* Truncate characters from beginning of line. */ 786 /* Number of characters to truncate. */ 787 { 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'; 793 } 794 } 795 /* _________________________________________________________________ */ 796 797 static void 798 endtrunc(int n) /* Truncate characters from end of line. */ 799 /* Number of characters to truncate. */ 800 { 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'; 808 } 809 } 810 811 static void 812 inputtabs(int p) /* Expand according to input tab specifications. */ 813 /* Pointer to tab specification. */ 814 { 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 */ 820 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++; 837 } 838 tabs++; 839 break; 840 default: 841 *tlast++ = c; 842 logcol++; 843 break; 844 } 845 } 846 pfirst = tfirst; 847 plast = --tlast; 848 } 849 /* 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. 860 */ 861 static void 862 sstrip(void) 863 { 864 int i, k; 865 char *c, *savec; 866 867 k = -1; 868 c = pfirst; 869 while (*c != '\t' && *c != '\n') { 870 k++; 871 c++; 872 } 873 if (*c != '\t') { 874 (void) fprintf(stderr, "not -s format\r\n"); 875 exit(1); 876 } 877 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] = '*'; 883 884 pfirst = ++savec; /* Point pfirst to char after tab */ 885 } 886 /* ================================================================= */ 887 888 static void 889 sadd(void) 890 { 891 int i; 892 893 for (i = 0; i <= savek; i++) *plast++ = savchr[i]; 894 *plast = '\n'; 895 } 896 897 static void 898 outputtabs(int p) /* Contract according to output tab specifications. */ 899 /* Pointer to tab specification. */ 900 { 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 */ 907 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++; 928 } 929 } while (*pfirst++ == ' '); 930 pfirst--; 931 break; 932 default: 933 logcol++; 934 *tlast++ = c; 935 break; 936 } 937 } 938 pfirst = tfirst; 939 plast = --tlast; 940 } 941