PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/usr/src/cmd/newform/newform.c

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