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