aboutsummaryrefslogtreecommitdiffstats
path: root/utils/Spiff/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/Spiff/output.c')
-rw-r--r--utils/Spiff/output.c558
1 files changed, 558 insertions, 0 deletions
diff --git a/utils/Spiff/output.c b/utils/Spiff/output.c
new file mode 100644
index 0000000..3db9044
--- /dev/null
+++ b/utils/Spiff/output.c
@@ -0,0 +1,558 @@
+/* Copyright (c) 1988 Bellcore
+** All Rights Reserved
+** Permission is granted to copy or use this program, EXCEPT that it
+** may not be sold for profit, the copyright notice must be reproduced
+** on copies, and credit should be given to Bellcore where it is due.
+** BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
+*/
+
+
+#ifndef lint
+static char rcsid[]= "$Header$";
+#endif
+
+#include <stdio.h>
+
+#ifdef M_TERMINFO
+#include <curses.h>
+#include <term.h>
+#endif
+
+#ifdef M_TERMCAP
+#ifdef XENIX
+#include <tcap.h>
+#endif
+#endif
+
+#include "misc.h"
+#include "flagdefs.h"
+#include "edit.h"
+#include "line.h"
+#include "token.h"
+
+static int _O_need_init = 1;
+static int _O_st_ok = 0;
+static int _O_doing_ul = 0;
+static char *_O_st_tmp;
+#ifdef M_TERMCAP
+static char _O_startline[Z_WORDLEN];
+static char _O_endline[Z_WORDLEN];
+#endif
+
+static void
+_O_st_init()
+{
+ char termn[Z_WORDLEN];
+#ifdef M_TERMCAP
+ static char entry[1024];
+#endif
+
+ /*
+ ** see if standard out is a terminal
+ */
+ if (!isatty(1))
+ {
+ _O_need_init = 0;
+ _O_st_ok = 0;
+ return;
+ }
+
+ if (NULL == (_O_st_tmp = (char*) getenv("TERM")))
+ {
+ Z_complain("can't find TERM entry in environment\n");
+ _O_need_init = 0;
+ _O_st_ok = 0;
+ return;
+ }
+ (void) strcpy(termn,_O_st_tmp);
+
+#ifdef M_TERMCAP
+ if (1 != tgetent(entry,termn))
+ {
+ Z_complain("can't get TERMCAP info for terminal\n");
+ _O_need_init = 0;
+ _O_st_ok = 0;
+ return;
+ }
+
+ _O_st_tmp = _O_startline;
+ _O_startline[0] = '\0';
+ tgetstr("so",&_O_st_tmp);
+
+ _O_st_tmp = _O_endline;
+ _O_endline[0] = '\0';
+ tgetstr("se",&_O_st_tmp);
+
+ _O_st_ok = (strlen(_O_startline) > 0) && (strlen(_O_endline) > 0);
+#endif
+
+#ifdef M_TERMINFO
+ setupterm(termn,1,&_O_st_ok);
+#endif
+ _O_need_init = 0;
+}
+
+void
+O_cleanup()
+{
+ /*
+ ** this probably isn't necessary, but in the
+ ** name of compeleteness.
+ */
+#ifdef M_TERMINFO
+ resetterm();
+#endif
+}
+
+static void
+_O_start_standout()
+{
+ if (_O_need_init)
+ {
+ _O_st_init();
+ }
+ if (_O_st_ok)
+ {
+#ifdef M_TERMCAP
+ (void) printf("%s",_O_startline);
+#endif
+#ifdef M_TERMINFO
+ vidattr(A_STANDOUT);
+#endif
+ }
+ else
+ {
+ _O_doing_ul = 1;
+ }
+}
+
+static void
+_O_end_standout()
+{
+ if (_O_need_init)
+ {
+ _O_st_init();
+ }
+ if (_O_st_ok)
+ {
+#ifdef M_TERMCAP
+ (void) printf("%s",_O_endline);
+#endif
+#ifdef M_TERMINFO
+ vidattr(0);
+#endif
+ }
+ else
+ {
+ _O_doing_ul = 0;
+ }
+}
+
+static void
+_O_pchars(line,start,end)
+char *line;
+int start,end;
+{
+ int cnt;
+
+ for(cnt=start;cnt < end; cnt++)
+ {
+ if (_O_doing_ul)
+ {
+ (void) putchar('_');
+ (void) putchar('\b');
+ }
+ (void) putchar(line[cnt]);
+ }
+}
+
+
+/*
+** convert a 0 origin token number to a 1 orgin token
+** number or 1 origin line number as appropriate
+*/
+static
+_O_con_line(numb,flags,filenum)
+int numb, flags,filenum;
+{
+ if (flags & U_TOKENS)
+ {
+ return(numb+1);
+ }
+ else
+ {
+ /*
+ ** check to make sure that this is a real
+ ** line number. if not, then return 0
+ ** on rare occasions, (i.e. insertion/deletion
+ ** of the first token in a file) we'll get
+ ** line numbers of -1. the usual look-up technique
+ ** won't work since we have no lines before than 0.
+ */
+ if (numb < 0)
+ return(0);
+ /*
+ ** look up the line number the token and then
+ ** add 1 to make line number 1 origin
+ */
+ return(L_tl2cl(filenum,numb)+1);
+ }
+}
+
+static char *
+_O_convert(ptr)
+char *ptr;
+{
+ static char spacetext[Z_WORDLEN];
+
+ if (1 == strlen(ptr))
+ {
+ switch (*ptr)
+ {
+ default:
+ break;
+ case '\n' :
+ (void) strcpy(spacetext,"<NEWLINE>");
+ return(spacetext);
+ case '\t' :
+ (void) strcpy(spacetext,"<TAB>");
+ return(spacetext);
+ case ' ' :
+ (void) strcpy(spacetext,"<SPACE>");
+ return(spacetext);
+ }
+
+ }
+ return(ptr);
+}
+
+static char*
+_O_get_text(file,index,flags)
+int file,index,flags;
+{
+ static char buf[Z_LINELEN*2]; /* leave lots of room for both
+ the token text and the
+ chatter that preceeds it */
+ char *text;
+ K_token tmp;
+
+ if (flags & U_TOKENS)
+ {
+ tmp = K_gettoken(file,index);
+ text = _O_convert(K_gettext(tmp));
+ (void) sprintf(buf,"%s -- line %d, character %d\n",
+ text,
+ /*
+ ** add 1 to make output start at line 1
+ ** and character numbers start at 1
+ */
+ L_tl2cl(file,K_getline(tmp))+1,
+ K_getpos(tmp)+1);
+ return(buf);
+ }
+ else
+ {
+ return(L_gettline(file,index));
+ }
+}
+#define _O_APP 1
+#define _O_DEL 2
+#define _O_CHA 3
+#define _O_TYPE_E 4
+
+static void
+_O_do_lines(start,end,file)
+int start,end,file;
+{
+ int cnt;
+ int lastline = -1;
+ int nextline;
+ K_token nexttoken;
+ for (cnt=start;cnt <= end; cnt++)
+ {
+ nexttoken = K_get_token(file,cnt);
+ nextline = K_getline(nexttoken);
+ if (lastline != nextline)
+ {
+ int lastone,lastchar;
+ K_token lasttok;
+ char linetext[Z_LINELEN+1]; /* leave room for
+ terminator */
+ if (0 == file)
+ {
+ (void) printf("< ");
+ }
+ else
+ {
+ (void) printf("> ");
+ }
+
+ /*
+ ** put loop here if you want to print
+ ** out any intervening lines that don't
+ ** have any tokens on them
+ */
+
+ /*
+ ** following line is necessary because
+ ** L_gettline is a macro, and can't be passed
+ */
+ (void) strcpy(linetext,L_gettline(file,nextline));
+ _O_pchars(linetext,0,K_getpos(nexttoken));
+ _O_start_standout();
+ /*
+ ** look for last token on this line to be
+ ** highlighted
+ */
+ for ( lastone=cnt,lasttok = K_get_token(file,lastone);
+ (lastone<=end)&&(nextline == K_getline(lasttok));
+ lastone++,lasttok = K_get_token(file,lastone))
+ {
+ }
+ lastone--;
+ lasttok = K_get_token(file,lastone);
+ lastchar = K_getpos(lasttok)
+ + strlen(K_gettext(lasttok));
+ _O_pchars(linetext,K_getpos(nexttoken),lastchar);
+ _O_end_standout();
+ _O_pchars(linetext,lastchar,strlen(linetext));
+
+ lastline = nextline;
+ }
+ }
+}
+
+void
+O_output(start,flags)
+E_edit start;
+int flags;
+{
+ int type = _O_TYPE_E; /* initialize to error state
+ ** this is to make sure that type is set
+ ** somewhere
+ */
+ int t_beg1, t_beg2, t_end1, t_end2; /* token numbers */
+ int first1, last1, first2, last2;
+
+ E_edit ep, behind, ahead, a, b;
+
+ /*
+ ** reverse the list of edits
+ */
+ ahead = start;
+ ep = E_NULL;
+ while (ahead != E_NULL) {
+ /*
+ ** set token numbers intentionally out of range
+ ** as boilerplate
+ */
+ t_beg1 = t_beg2 = t_end1 = t_end2 = -1;
+ /*
+ ** edit script is 1 origin, all of
+ ** our routines are zero origin
+ */
+ E_setl1(ahead,(E_getl1(ahead))-1);
+ E_setl2(ahead,(E_getl2(ahead))-1);
+
+ behind = ep;
+ ep = ahead;
+ ahead = E_getnext(ahead);
+ E_setnext(ep,behind);
+ }
+
+ /*
+ ** now run down the list and collect the following information
+ ** type of change (_O_APP, _O_DEL or _O_CHA)
+ ** start and length for each file
+ */
+ while (ep != E_NULL)
+ {
+ b = ep;
+ /*
+ ** operation always start here
+ */
+ t_beg1 = E_getl1(ep);
+ /*
+ ** any deletions will appear before any insertions,
+ ** so, if the first edit is an E_INSERT, then this
+ ** this is an _O_APP
+ */
+ if (E_getop(ep) == E_INSERT)
+ type = _O_APP;
+ else {
+ /*
+ ** run down the list looking for the edit
+ ** that is not part of the current deletion
+ */
+ do {
+ a = b;
+ b = E_getnext(b);
+ } while ((b != E_NULL) &&
+ (E_getop(b) == E_DELETE) &&
+ ((E_getl1(b)) == ((E_getl1(a))+1)));
+ /*
+ ** if we have an insertion at the same place
+ ** as the deletion we just scanned, then
+ ** this is a change
+ */
+ if ((b != E_NULL) &&
+ ((E_getop(b)) == E_INSERT) &&
+ ((E_getl1(b))==(E_getl1(a))))
+ {
+ type = _O_CHA;
+ }
+ else
+ {
+ type = _O_DEL;
+ }
+ /*
+ ** set up start and length information for
+ ** first file
+ */
+ t_end1 = E_getl1(a);
+ /*
+ ** move pointer to beginning of insertion
+ */
+ ep = b;
+ /*
+ ** if we are showing only a deletion,
+ ** then we're all done, so skip ahead
+ */
+ if (_O_DEL == type)
+ {
+ t_beg2 = E_getl2(a);
+ t_end2 = -1; /* dummy number, won't
+ ever be printed */
+
+ goto skipit;
+ }
+ }
+ t_beg2 = E_getl2(ep);
+ t_end2 = t_beg2-1;
+ /*
+ ** now run down the list lookingfor the
+ ** end of this insertion and keep count
+ ** of the number of times we step along
+ */
+ do {
+ t_end2++;
+ ep = E_getnext(ep);
+ } while ((ep != E_NULL) && ((E_getop(ep)) == E_INSERT) &&
+ ((E_getl1(ep)) == (E_getl1(b))));
+
+skipit:;
+ if (flags & U_TOKENS)
+ {
+ /*
+ ** if we are dealing with tokens individually,
+ ** then just print then set printing so
+ */
+ first1 = t_beg1;
+ last1 = t_end1;
+ first2 = t_beg2;
+ last2 = t_end2;
+ }
+ else
+ {
+ /*
+ ** we are printing differences in terms of lines
+ ** so find the beginning and ending lines of the
+ ** changes and print header in those terms
+ */
+ if ( t_beg1 >= 0)
+ first1 = K_getline(K_get_token(0,t_beg1));
+ else
+ first1 = t_beg1;
+
+ if ( t_end1 >= 0)
+ last1 = K_getline(K_get_token(0,t_end1));
+ else
+ last1 = t_end1;
+
+ if ( t_beg2 >= 0)
+ first2 = K_getline(K_get_token(1,t_beg2));
+ else
+ first2 = t_beg2;
+
+ if ( t_end2 >= 0)
+ last2 = K_getline(K_get_token(1,t_end2));
+ else
+ last2 = t_end2;
+
+ }
+ /*
+ ** print the header for this difference
+ */
+ (void) printf("%d",_O_con_line(first1,flags,0));
+ switch (type)
+ {
+ case _O_APP :
+ (void) printf("a%d",_O_con_line(first2,flags,1));
+ if (last2 > first2)
+ {
+ (void) printf(",%d",_O_con_line(last2,flags,1));
+ }
+ (void) printf("\n");
+ break;
+ case _O_DEL :
+ if (last1 > first1)
+ {
+ (void) printf(",%d",_O_con_line(last1,flags,0));
+ }
+ (void) printf("d%d\n",_O_con_line(first2,flags,1));
+ break;
+ case _O_CHA :
+ if (last1 > first1)
+ {
+ (void) printf(",%d",_O_con_line(last1,flags,0));
+ }
+ (void) printf("c%d",_O_con_line(first2,flags,1));
+ if (last2 > first2)
+ {
+ (void) printf(",%d",_O_con_line(last2,flags,1));
+ }
+ (void) printf("\n");
+ break;
+ default:
+ Z_fatal("type in O_output wasn't set\n");
+ }
+ if (_O_DEL == type || _O_CHA == type)
+ {
+ if (flags & U_TOKENS)
+ {
+ int cnt;
+ for(cnt=first1;cnt <= last1; cnt++)
+ {
+ (void) printf("< %s",
+ _O_get_text(0,cnt,flags));
+ }
+ }
+ else
+ {
+ _O_do_lines(t_beg1,t_end1,0);
+ }
+ }
+ if (_O_CHA == type)
+ {
+ (void) printf("---\n");
+ }
+ if (_O_APP == type || _O_CHA == type)
+ {
+ if (flags & U_TOKENS)
+ {
+ int cnt;
+ for(cnt=first2;cnt <= last2; cnt++)
+ {
+ (void) printf("> %s",
+ _O_get_text(1,cnt,flags));
+ }
+ }
+ else
+ {
+ _O_do_lines(t_beg2,t_end2,1);
+ }
+ }
+ }
+ O_cleanup();
+ return;
+}