#include #include #include #include #include #include "config.h" #include #ifdef USING_STD_STRING using std::string; #endif #ifdef DMALLOC #include #endif #include "echo.h" #include "defines.h" #include "support.h" #include "tcltk.h" extern char currentwindow[20]; void parse_ansi_code(char *data, int *bold, int *underline, int *fg, int *bg, int *reversefg, int *reversebg, char *pathname) { int reverse=0; int n; char* position=strtok(data,";"); while(position) { n=atoi(position); switch(n) { case 0: *bold=0; *underline=0; *fg=TT_IntF(TT_ARGS,"set ::dynamic::theme_[windowtype %s]_foreground",pathname); *bg=TT_IntF(TT_ARGS,"set ::dynamic::theme_[windowtype %s]_background",pathname); *reversefg=*fg; *reversebg=*bg; break; case 1: *bold=1; break; case 4: *underline=1; break; case 7: reverse=1; break; case 30: *reversefg=1; *fg=1; break; case 31: *reversefg=4; *fg=4; break; case 32: *reversefg=9; *fg=9; break; case 33: *reversefg=8; *fg=8; break; case 34: *reversefg=12; *fg=12; break; case 35: *reversefg=13; *fg=13; break; case 36: *reversefg=11; *fg=11; break; case 37: *reversefg=0; *fg=0; break; case 40: *reversebg=1; *bg=1; break; case 41: *reversebg=4; *bg=4; break; case 42: *reversebg=9; *bg=9; break; case 43: *reversebg=8; *bg=8; break; case 44: *reversebg=12; *bg=12; break; case 45: *reversebg=13; *bg=13; break; case 46: *reversebg=11; *bg=11; break; case 47: *reversebg=0; *bg=0; break; } position=strtok(NULL,";"); } if(reverse) { *fg=*reversebg; *bg=*reversefg; } // ;...m // 0 - All attributes off // 1 - Bold on // 4 - Underscore // 5 - Blink (Not handled!) // 7 - Reverse video on // 8 - Concealed on (Not handled!) // Foreground // 30 - Black (1) // 31 - Red (4) // 32 - Green (9) // 33 - Yellow (8) // 34 - Blue (12) // 35 - Magenta (13) // 36 - Cyan (11) // 37 - White (0) // Foreground // 40 - Black (1) // 41 - Red (4) // 42 - Green (9) // 43 - Yellow (8) // 44 - Blue (12) // 45 - Magenta (13) // 46 - Cyan (11) // 47 - White (0) } void echotags(Tcl_Obj *strobj, char *path, int newtext) { Tcl_Obj *objptr; int len; char* str; if(!path) path=currentwindow; // What's the deal here? if(!strlen(path)) return; str=Tcl_GetStringFromObj(strobj,&len); if(len) { TT_EvalF(TT_ARGS,"%s.text configure -state normal",path); objptr=Tcl_NewStringObj(path,strlen(path)); Tcl_IncrRefCount(objptr); Tcl_AppendStringsToObj(objptr,".text insert end ",NULL); Tcl_AppendToObj(objptr, str, len); if(TCL_ERROR==Tcl_GlobalEvalObj(TT_Interp,objptr)) { Tcl_VarEval(TT_Interp,"bgerror \"File: ",__FILE__," Line: ",strnum(__LINE__),"\"",0); } TT_EvalF(TT_ARGS,"%s.text configure -state disabled",path); Tcl_DecrRefCount(objptr); } if(!strcmp(path,currentwindow)) { TT_EvalF(TT_ARGS,"\ if { [lindex \"[%s.text_vscroll get]\" 1]==1.0 } { %s.text yview moveto 1 }\ ",path,path); } else { if(newtext) TT_EvalF(TT_ARGS,"activebutton %s",path); TT_EvalF(TT_ARGS,"%s.text yview moveto 1",path); } } void gettags_current(char *path, string ¤tpiece, int bold, int underline, int fg, int bg, Tcl_Obj* objptr, int *substance) { char tag[10]; char *dst; int flags; int length; tag[0]=0; if(currentpiece.length()>0) { if(*substance) Tcl_AppendStringsToObj(objptr," ",NULL); *substance=1; sprintf(tag,"%d,%d",fg%16,bg%16); if(bold) strcat(tag,"b"); if(underline) strcat(tag,"u"); dst=(char *)malloc(Tcl_ScanCountedElementFixed(currentpiece.data(),currentpiece.length(),&flags)); flags|=TCL_DONT_USE_BRACES; length=Tcl_ConvertCountedElement(currentpiece.data(), currentpiece.length(), dst, flags); Tcl_AppendToObj(objptr,dst,length); free(dst); Tcl_AppendStringsToObj(objptr," ",tag,NULL); currentpiece=""; } } Tcl_Obj *gettags(Tcl_Obj *strobj, char *path) { int bold=0; int underline=0; int default_foreground; int default_background; int reversefg, reversebg; int fg, bg; string currentpiece; char ansicode[TEMPLEN]; char col[3]={0}; int temp; int n, i; int parsed; int state; int dobreak; Tcl_Obj *objptr; int substance; char *message; int length; // Path must be a valid pathname or a null pointer, not an empty string. // What if we remove this entirely forcing it to be a valid single pathname? if(!path) path=currentwindow; default_foreground=TT_IntF(TT_ARGS,"set ::dynamic::theme_[windowtype %s]_foreground",path); default_background=TT_IntF(TT_ARGS,"set ::dynamic::theme_[windowtype %s]_background",path); reversefg=default_foreground; reversebg=default_background; fg=default_foreground; bg=default_background; message=Tcl_GetStringFromObj(strobj,&length); objptr=Tcl_NewStringObj("",0); Tcl_IncrRefCount(objptr); if(length) { substance=0; for(n=0;n='0')&&(message[n]<='9')) { col[0]=message[n]; col[1]=0; state=1; } else { reversebg=default_background; reversefg=default_foreground; bg=default_background; fg=default_foreground; n--; state=100; } break; case 1: /* If we are here, we have a first char */ if(message[n]==',') { reversefg=atoi(col); fg=atoi(col); state=10; } else if((message[n]>='0')&&(message[n]<='9')) { col[1]=message[n]; reversefg=atoi(col); fg=atoi(col); state=9; } else { reversefg=atoi(col); fg=atoi(col); n--; state=100; } break; case 9: /* If this state occurs we are waiting for a comma or an EOC */ if(message[n]==',') { state=10; } else { n--; state=100; } break; case 10: /* If we are here, we have a comma */ if((message[n]>='0')&&(message[n]<='9')) { col[0]=message[n]; col[1]=0; state=11; } else { reversebg=default_background; bg=default_background; n--; state=100; } break; case 11: /* If we are here, we have a first char of second set */ if((message[n]>='0')&&(message[n]<='9')) { col[1]=message[n]; reversebg=atoi(col); bg=atoi(col); state=100; } else { reversebg=atoi(col); bg=atoi(col); n--; state=100; } break; default: break; } } } if(message[n]==0x1b) { n++; if(message[n]=='[') { n++; gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance); strcpy(ansicode,message+n); dobreak=0; for(i=0;i<(signed)strlen(ansicode);i++) { switch(ansicode[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ';': n++; break; case '\033': dobreak=1; break; case 'm': ansicode[i]=0; parse_ansi_code(ansicode,&bold,&underline,&fg,&bg,&reversefg,&reversebg,path); default: n++; dobreak=1; break; } if(dobreak) break; } } parsed=1; n--; // [0;34;42mtest } if(!parsed) { currentpiece+=message[n]; } } gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance); } return objptr; } void echo_n(Tcl_Obj *strobj, char *path, int newtext) { Tcl_Obj *objs[4]; Tcl_Obj *objptr; Tcl_Obj *newobjptr=0; int len; // Why DO we need this? if(!strlen(path)) return; /* K, first check for the event_echo. If it's there, run it with our magical text that we got. Then, take the returned text object and shove it through gettags. If gettags returns something with lenth !zero, output a newline and do echotags on the result from gettags. Proceed to decrement the gettags object result counter. */ if(TT_Int(TT_ARGS,"expr {\"[info procs event_echo]\"!=\"\"}")) { objs[0]=Tcl_NewStringObj("event_echo",10); objs[1]=strobj; objs[2]=Tcl_NewStringObj(path,strlen(path)); if(newtext) { objs[3]=Tcl_NewStringObj("1",1); } else { objs[3]=Tcl_NewStringObj("0",1); } objptr=Tcl_NewListObj(4,objs); Tcl_IncrRefCount(objptr); if(TCL_ERROR==Tcl_GlobalEvalObj(TT_Interp,objptr)) { Tcl_VarEval(TT_Interp,"bgerror \"File: ",__FILE__," Line: ",strnum(__LINE__),"\"",0); } Tcl_DecrRefCount(objptr); objptr=Tcl_GetObjResult(TT_Interp); Tcl_IncrRefCount(objptr); Tcl_GetStringFromObj(objptr,&len); if(len) { newobjptr=gettags(objptr,path); } Tcl_DecrRefCount(objptr); } else { objptr=strobj; newobjptr=gettags(objptr,path); } if(newobjptr) { TT_EvalF(TT_ARGS,"%s.text configure -state normal",path); TT_EvalF(TT_ARGS,"%s.text insert end \"\\n\"",path); echotags(newobjptr,path,newtext); Tcl_DecrRefCount(newobjptr); } } void echo(char *message, char *path, int newtext) { Tcl_Obj *strobj; strobj=Tcl_NewStringObj(message,strlen(message)); Tcl_IncrRefCount(strobj); echo_n(strobj,path,newtext); Tcl_DecrRefCount(strobj); }