#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include "config.h"
#include <string>
#ifdef USING_STD_STRING
using std::string;
#endif
#ifdef DMALLOC
#include <dmalloc.h>
#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;
}
// [n;...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<length;n++) {
parsed=0;
if(message[n]==0x02) {
parsed=1;
gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance);
bold=1-bold;
}
if(message[n]==0x16) {
parsed=1;
gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance);
temp=fg;
fg=bg;
bg=temp;
}
if(message[n]==0x1f) {
parsed=1;
gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance);
underline=1-underline;
}
if(message[n]==0x0f) {
parsed=1;
gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance);
bold=0;
underline=0;
reversebg=default_background;
reversefg=default_foreground;
bg=default_background;
fg=default_foreground;
}
if(message[n]==0) {
parsed=1;
}
if(message[n]==0x03) {
parsed=1;
gettags_current(path,currentpiece,bold,underline,fg,bg,objptr,&substance);
state=0;
while(state!=100) {
n++;
switch(state) {
case 0:
/* We just found a \x03 */
if(message[n]==',') {
reversefg=default_foreground;
fg=default_foreground;
state=10;
} else if((message[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);
}
syntax highlighted by Code2HTML, v. 0.9.1