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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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