home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!rs
- From: rs@uunet.UU.NET (Rich Salz)
- Newsgroups: comp.sources.unix
- Subject: v10i070: A "changebar" interface for *roff
- Message-ID: <735@uunet.UU.NET>
- Date: 30 Jul 87 22:21:03 GMT
- Organization: UUNET Communications Services, Arlington, VA
- Lines: 585
- Approved: rs@uunet.UU.NET
-
- Submitted-by: tektronix!tessi!bobl (Bob Lewis)
- Posting-number: Volume 10, Issue 70
- Archive-name: nrchbar
-
- [ This program works with diff on ostensible Unix formatter input to
- output formatting codes to do changebars. Very nice. --r$ ]
-
- #!/bin/sh
- # to extract, remove the header and type "sh filename"
- if `test ! -s ./README`
- then
- echo "writing ./README"
- cat > ./README << '\Rogue\Monster\'
- The "nrchbar" program effectively inserts n/troff-style change bar commands
- into files which are (presumably) n/troff source. For more information,
- consult the man page.
-
- To install "nrchbar":
-
- 1) Inspect "Makefile" for proper destinations (currently,
- "/usr/local/bin" for the binary and "/usr/man/manl" for the man
- page). Correct these if necessary. If "diff" on your system isn't
- "/bin/diff", you'll also need to modify the "DIFFPROG" #define in
- "nrchbar.c". "nrchbar" assumes "getopt" is present, so you'll need
- to contact your friendly neighborhood comp.sources.unix archive if it
- isn't.
-
- 2) In the source directory:
-
- % make install
-
- 3) If everything goes well, still in the source directory:
-
- % make clean
-
- I claim that this program was written entirely by me, entitling me (with the
- approval of my management) to release it into the public domain, which I now
- do. However, I make no warrantees, either express or implied, on "nrchbar"
- or its associated files and I do not assume responsiblity for any damages
- resulting from its installation or use.
-
- The software has only been compiled and tested on a Sun 3/50, but I don't
- expect any major problems on other UNIX machines, including System V.
-
- In spite of the disclaimer above, I'd like to hear about bugs and/or feature
- requests.
-
- Acknowledgements and thanks to Robert Reed of Tektronix, who wrote the
- original shell script; and to Jeff Hahs, Ron Lunde, Charlie Mills, and Bill
- den Beste of TSSI for encouragement, ideas, and testing.
-
- - Bob Lewis
- Test Systems Strategies, Inc.
- 8205 SW Creekside Pl.
- Beaverton, OR 97005
- (503) 643-9281
-
- ...!tektronix!tessi!bobl or bobl@tessi.UUCP
-
- \Rogue\Monster\
- else
- echo "will not over write ./README"
- fi
- if `test ! -s ./Makefile`
- then
- echo "writing ./Makefile"
- cat > ./Makefile << '\Rogue\Monster\'
- SRC = nrchbar.c
-
- BIN = nrchbar
- BINDEST = /usr/local/bin
-
- MAN = nrchbar.1
- MANDEST = /usr/man/manl
-
- SHARNAME = nrchbar
-
- $(BIN): $(SRC)
- cc -O -o $(BIN) $(SRC)
-
- clean:
- rm -f $(BIN) *.o core a.out
-
- install: $(BIN) $(MAN)
- install -s $(BIN) $(BINDEST)
- cp $(MAN) $(MANDEST)
-
- lint: $(SRC)
- lint -bchx $(SRC)
-
- shar: README Makefile $(SRC) $(MAN)
- shar -f $(SHARNAME) README Makefile $(SRC) $(MAN)
- \Rogue\Monster\
- else
- echo "will not over write ./Makefile"
- fi
- if `test ! -s ./nrchbar.c`
- then
- echo "writing ./nrchbar.c"
- cat > ./nrchbar.c << '\Rogue\Monster\'
- /* nrchbar -- insert nroff change bar commands into a file */
-
- #include <stdio.h>
-
- #define DIFFPROG "/bin/diff"
-
- typedef int bool;
- #define TRUE 1
- #define FALSE 0
-
- #define ADD 'a'
- #define CHANGE 'c'
- #define DELETE 'd'
-
- typedef struct {
- int lnOldFrom;
- int lnOldTo;
- int cmd;
- int lnNewFrom;
- int lnNewTo;
- } diffdescr;
-
- char *progname;
- bool flagAll = FALSE;
- bool flagBreakAfter = TRUE;
- bool flagDelete = FALSE;
-
- /* forward declarations */
- FILE *fopenOrElse();
- void nrchbar();
- FILE *pipeDiffs();
- void skipLinesOrElse();
- void userErr();
-
- #ifndef lint
- char *rcsid = "$Header: nrchbar.c,v 1.3 87/03/31 16:33:16 bobl Exp $";
- #endif
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- extern int optind;
- FILE *fpDiff, *fpNew;
- char *fnOld, *fnNew;
-
- progname = argv[0];
- while ((c = getopt(argc, argv, "abd")) != EOF)
- switch (c) {
-
- case 'a':
- flagAll = TRUE;
- break;
-
- case 'b':
- flagBreakAfter = FALSE;
- break;
-
- case 'd':
- flagDelete = TRUE;
- break;
-
- case '?':
- (void) fprintf(stderr, "%s: unknown flag \"-%c\"\n", c);
- exit(1);
- break;
- }
-
-
- /*
- * Depending on the number of files on the command line.
- */
- switch (argc - optind) {
-
- case 1:
- fpDiff = stdin;
- fnNew = argv[optind++];
- fpNew = fopenOrElse(fnNew, "r");
- break;
-
- case 2:
- fnOld = argv[optind++];
- fnNew = argv[optind++];
- fpDiff = pipeDiffs(fnOld, fnNew);
- fpNew = fopenOrElse(fnNew, "r");
- break;
-
- default:
- (void) fprintf(stderr, "Usage: %s [ -a ] [ -b ] [ -d ] [ <old> ] new\n", progname);
- exit(1);
- }
- /*
- * Now the real work begins.
- */
- nrchbar(fpDiff, fpNew);
-
- exit(0);
- }
-
- /* beginChbar -- put out a *roff command to begin a change bar */
- void beginChbar(chMark)
- int chMark; /* in: use this character */
- {
- (void) printf(".mc %c\n", chMark);
- return;
- }
-
- /* copyLines -- copy a given number of lines from one file to standard output */
- bool copyLines(nLn, nSkip, fpFrom)
- int nLn; /* in: copy this many lines ... */
- int nSkip; /* in: ... skipping this many characters at the start of each one ... */
- FILE *fpFrom; /* in: ... from this file to stdout */
- {
- int ch;
- int iSkip;
-
- while (nLn-- > 0) {
- for (iSkip = 0; iSkip < nSkip; iSkip++)
- if (getc(fpFrom) == EOF)
- return FALSE;
- do {
- ch = getc(fpFrom);
- if (ch == EOF)
- return FALSE;
- putchar(ch);
- } while (ch != '\n');
- }
-
- return TRUE;
- }
-
- /* copyLinesOrElse -- copy a given number of lines from one file to standard output; exit if unable */
- void copyLinesOrElse(nLn, nSkip, fpFrom)
- int nLn; /* in: copy this many lines ... */
- int nSkip; /* in: ... skipping this many characters at the start of each one ... */
- FILE *fpFrom; /* in: ... from this file to stdout */
- {
- if (!copyLines(nLn, nSkip, fpFrom))
- userErr("unexpected EOF");
- return;
- }
-
- /* endChbar -- put out a *roff command to end a change bar section */
- void endChbar()
- {
- if (flagBreakAfter)
- (void) printf(".br\n"); /* make sure the previous change bar is visible */
- (void) printf(".mc\n");
- return;
- }
-
- /* fopenOrElse -- open a file or else exit with an error message */
- FILE *fopenOrElse(fname, type)
- char *fname; /* in: file name to open */
- char *type; /* in: way in which to open fname */
- {
- FILE *fp = fopen(fname, type);
-
- if (fp == NULL) {
- (void) fprintf(stderr, "%s: can't open \"%s\" for mode \"%s\"\n",
- progname, fname, type);
- exit(1);
- }
- return fp;
- }
-
- /* getDiff -- get a "diff" description line */
- int getDiff(fp, ddscr)
- FILE *fp; /* in: file containing "diff" output */
- diffdescr *ddscr; /* in: a diff section descriptor */
- {
- #define EOA 0
- #define START_ACCUM 1
- #define ACCUM 2
- #define SET_OLD_FROM 3
- #define SET_OLD_TO 4
- #define SET_CMD 5
- #define SET_NEW_FROM 6
- #define SET_NEW_TO 7
- #define MXN_ACTION 8
- static struct {
- int state;
- char *trig;
- int stateNext;
- int action[MXN_ACTION];
- } fsm[] = {
- { 0, "0123456789", 1, { START_ACCUM, EOA } },
- { 1, "0123456789", 1, { ACCUM, EOA } },
- { 1, ",", 2, { SET_OLD_FROM, EOA } },
- { 1, "acd", 4, { SET_OLD_FROM, SET_OLD_TO, SET_CMD, EOA } },
- { 2, "123456789", 3, { START_ACCUM, EOA } },
- { 3, "0123456789", 3, { ACCUM, EOA } },
- { 3, "acd", 4, { SET_OLD_TO, SET_CMD, EOA } },
- { 4, "0123456789", 5, { START_ACCUM, EOA } },
- { 5, "0123456789", 5, { ACCUM, EOA } },
- { 5, ",", 6, { SET_NEW_FROM, EOA } },
- { 5, "\n", -1, { SET_NEW_FROM, SET_NEW_TO, EOA } },
- { 6, "123456789", 7, { START_ACCUM, EOA } },
- { 7, "0123456789", 7, { ACCUM, EOA } },
- { 7, "\n", -1, { SET_NEW_TO, EOA } },
- { -1, (char *) NULL, -1, { EOA } } /* sentinal */
- }, *fsmCur;
- int stateCur = 0;
- int ch, accum = 0;
- int *action;
- int len = 0;
- extern char *index();
-
- do {
- ch = getc(fp);
- if (ch == EOF)
- return EOF;
- len++;
- fsmCur = &fsm[0];
- while (fsmCur->state != -1
- && (fsmCur->state != stateCur
- || index(fsmCur->trig, ch) == NULL))
- fsmCur++;
- if (fsmCur->state == -1)
- userErr("illegal syntax in 'diff' output");
- for (action = fsmCur->action; *action != EOA; action++)
- switch (*action) {
-
- case START_ACCUM:
- accum = ch - '0'; /* assume ASCII */
- break;
-
- case ACCUM:
- accum = 10*accum + (ch - '0'); /* assume ASCII */
- break;
-
- case SET_CMD:
- ddscr->cmd = ch;
- break;
-
- case SET_NEW_FROM:
- ddscr->lnNewFrom = accum;
- break;
-
- case SET_NEW_TO:
- ddscr->lnNewTo = accum;
- break;
-
- case SET_OLD_FROM:
- ddscr->lnOldFrom = accum;
- break;
-
- case SET_OLD_TO:
- ddscr->lnOldTo = accum;
- break;
- }
- stateCur = fsmCur->stateNext;
- } while (stateCur != -1);
-
- return len;
- }
-
- /* isRoffCmd -- return TRUE iff the next line begins with a *roff command */
- bool isRoffCmd(fp)
- FILE *fp; /* in: file to examine for *roff command */
- {
- int ch;
-
- if ((ch = getc(fp)) == EOF)
- userErr("unexpected EOF");
- (void) ungetc(ch, fp);
- return (ch == '.'); /* don't know about ".cc" command */
- }
-
- /* markDiff -- note a changed section of a file; return # of lines copied from fpNew */
- void markDiff(ddscr, fpDiff, fpNew)
- diffdescr *ddscr; /* in: descriptor of the differing sectinos */
- FILE *fpDiff; /* in: the diff file */
- FILE *fpNew; /* in: the new file */
- {
- int nLnNew = ddscr->lnNewTo - ddscr->lnNewFrom + 1;
- int nLnOld = ddscr->lnOldTo - ddscr->lnOldFrom + 1;
- int nLnNewCopy = nLnNew;
-
- switch (ddscr->cmd) {
-
- case ADD:
- if (!flagAll) {
- while (nLnNewCopy > 0 && isRoffCmd(fpNew)) {
- copyLinesOrElse(1, 0, fpNew);
- nLnNewCopy--;
- }
- }
- if (nLnNewCopy > 0) {
- beginChbar('+');
- copyLinesOrElse(nLnNewCopy, 0, fpNew);
- endChbar();
- }
- skipLinesOrElse(nLnNew, fpDiff);
- return;
-
- case CHANGE:
- if (!flagAll) {
- while (nLnNewCopy > 0 && isRoffCmd(fpNew)) {
- copyLinesOrElse(1, 0, fpNew);
- nLnNewCopy--;
- }
- }
- if (nLnNewCopy > 0) {
- beginChbar('|');
- copyLinesOrElse(nLnNewCopy, 0, fpNew);
- endChbar();
- }
- skipLinesOrElse(nLnNew + 1 + nLnOld, fpDiff); /* allow for "---" in diff */
- return;
-
- case DELETE:
- beginChbar('-');
- if (flagDelete) {
- putchar('[');
- putchar('[');
- putchar('\n');
- copyLinesOrElse(nLnOld, 2, fpDiff); /* strip off the "< " */
- putchar(']');
- putchar(']');
- putchar('\n');
- } else
- skipLinesOrElse(nLnOld, fpDiff);
- endChbar();
- return;
- }
- }
-
- /* nrchbar -- produce *roff change bar file */
- void nrchbar(fpDiff, fpNew)
- FILE *fpDiff; /* in: diff file */
- FILE *fpNew; /* in: original file */
- {
- int lnNew = 1;
- int nLines;
- diffdescr ddscr;
-
- while (getDiff(fpDiff, &ddscr) != EOF) {
- nLines = ddscr.lnNewFrom - lnNew;
- if (ddscr.cmd == DELETE)
- nLines++;
- copyLinesOrElse(nLines, 0, fpNew);
- markDiff(&ddscr, fpDiff, fpNew);
- lnNew = ddscr.lnNewTo + 1;
- }
- while (copyLines(1, 0, fpNew))
- ;
- return;
- }
-
- /* pipeDiffs -- return a pipe with a diff run on the other end */
- FILE *pipeDiffs(fnOld, fnNew)
- char *fnOld; /* in: old file name */
- char *fnNew; /* in: new file name */
- {
- char *cmd;
- FILE *fpPipe;
-
- cmd = (char *) malloc((unsigned int) (strlen(DIFFPROG) + 1 + strlen(fnOld) + 1 + strlen(fnNew) + 1));
- (void) sprintf(cmd, "%s %s %s", DIFFPROG, fnOld, fnNew);
- fpPipe = popen(cmd, "r");
- if (fpPipe == NULL) {
- (void) fprintf(stderr, "%s: can't open pipe for \"%s\"\n",
- progname, cmd);
- exit(1);
- }
- free(cmd);
- return fpPipe;
- }
-
- /* skipLinesOrElse -- skip a given number of lines in a file; exit if errors */
- void skipLinesOrElse(nLn, fp)
- int nLn; /* in: skip this many lines ... */
- FILE *fp; /* in: ... in this file */
- {
- int ch;
-
- while (nLn-- > 0) {
- do {
- if ((ch = getc(fp)) == EOF)
- userErr("unexpected EOF");
- } while (ch != '\n');
- }
- return;
- }
-
- /* userErr -- note an error and politely exude */
- void userErr(msg)
- char *msg;
- {
- (void) fprintf(stderr, "%s: %s\n", progname, msg);
- exit(1);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./nrchbar.c"
- fi
- if `test ! -s ./nrchbar.1`
- then
- echo "writing ./nrchbar.1"
- cat > ./nrchbar.1 << '\Rogue\Monster\'
- .\" $Header: nrchbar.1,v 1.2 87/03/31 16:33:02 bobl Exp $
- .TH NRCHBAR 1 "March 19, 1987"
- .SH NAME
- nrchbar \- insert n/troff-style change bars in a file
- .SH SYNOPSIS
- \fBnrchbar\fP [ \fB\-a\fP ] [ \fB\-b\fP ] [ \fB\-d\fP ] [ \fIoldfile\fP ] \fInewfile\fP
- .SH DESCRIPTION
- \fINrchbar\fP inserts commands suitable for
- .IR nroff (1)
- or
- .IR troff (1)
- (hereafter, "\fI*roff\fP") to produce "change bars" denoting
- differences between \fIoldfile\fP and \fInewfile\fP.
- It sends the result to standard output.
- .LP
- If \fIoldfile\fP is defaulted, \fInrchbar\fP assumes that its standard
- input will contain differences between \fIoldfile\fP and \fInewfile\fP
- in
- .IR diff (1)
- format.
- .LP
- By default, \fInrchbar\fP ignores changes to sections containing nothing
- but \fI*roff\fP commands, which it takes to be any lines beginning with
- ".".
- You can override this with the \fB\-a\fP option.
- .LP
- \fINrchbar\fP inserts \fI*roff\fP ".mc" commands to provide the change
- bars.
- This will place a character to the far right of each changed section.
- This character is a "+" for added sections, a "|" for
- modified sections, and a "-" for deleted sections.
- .LP
- By default, the text of deleted sections does not appear, but the
- \fB\-d\fP option will cause it to be inserted, surrounded by "[[" and "]]".
- .LP
- Also by default, \fInrchbar\fP puts a break (".br") command after each
- changed section.
- This is the only way to guarantee that deletions and small changes
- get flagged.
- The \fB\-b\fP option directs the program not to insert these breaks.
- It makes the text look more like \fI*roff\fPed
- \fInewfile\fP, but means that some change bars won't appear where
- they should.
- .SH PRONUNCIATION
- NERCH-bar
- .SH ETYMOLOGY
- NRoff CHange BAR
- .SH OPTIONS
- .IP \fB\-a\fP
- Put change bars around all changed sections, even if they consist of
- nothing but \fI*roff\fP commands.
- .IP \fB\-b\fP
- Do not insert breaks after changed sections.
- .IP \fB\-d\fP
- Show deleted text by preceding it with "[[" and following it with "]]".
- .SH SEE\ ALSO
- nroff(1), troff(1)
- .SH BUGS
- "." is always assumed to denote \fI*roff\fP commands.
- \fINrchbar\fP knows nothing about the ".cc" command.
- .LP
- The need for the \fB\-b\fP hack would disappear if there were a way
- to tell \fI*roff\fP "Turn off the change bar character at
- immediately after you put out this one.".
- A horizontal ".wh", perhaps?
- .LP
- The ".mc" command doesn't always work, especially with diversions.
- This is actually a \fI*roff\fP bug, but you ought to know about it.
- .LP
- \fINrchbar\fP may mess up tables, lists, or displays.
- For a really polished change bar document, you may want to edit
- its output before sending it to \fI*roff\fP.
- \Rogue\Monster\
- else
- echo "will not over write ./nrchbar.1"
- fi
- echo "Finished archive 1 of 1"
- exit
- --
-
- Rich $alz "Anger is an energy"
- Cronus Project, BBN Labs rsalz@bbn.com
- Moderator, comp.sources.unix sources@uunet.uu.net
-