/* 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: output.c,v 1.1 88/09/15 11:33:52 daniel Rel $"; #endif #include #ifdef M_TERMINFO #include #include #endif #ifdef M_TERMCAP #ifdef XENIX #include #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 extern char *getenv (); /* ** see if standard out is a terminal */ if (!isatty(1)) { _O_need_init = 0; _O_st_ok = 0; return; } #if amiga if (NULL == (_O_st_tmp = "ansi")) #else if (NULL == (_O_st_tmp = (char*) getenv("TERM"))) #endif { 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,""); return(spacetext); case '\t' : (void) strcpy(spacetext,""); return(spacetext); case ' ' : (void) strcpy(spacetext,""); 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; } #if amiga tgetent () { return (1); } tgetstr (str, where) char *str; char **where; { if (strcmp (str, "so")) { *where = "\033[7m"; } else if (strcmp (str, "se")) { *where = "\033[m"; } } #endif