diff options
Diffstat (limited to 'utils/Spiff/output.c')
-rw-r--r-- | utils/Spiff/output.c | 558 |
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; +} |