#include <strings.h>
#include <ctype.h>
#include <pwd.h>
#include <sys/types.h>
#ifdef DMALLOC
#include <dmalloc.h>
#endif
#include "messages.h"
#include "tcltk.h"
#include "illist.h"
#include "llist.h"
#include "window.h"
#include "channel.h"
#include "quirc.h"
void strlow(char *str) {
int i;
for ( i = 0; i < (signed)strlen(str) ; i++)
str[i] = tolower(str[i]);
}
char *strstrnc(char *haystack, const char *needle) {
char *h1;
char *n1;
char *result;
long rv;
h1 = strdup(haystack);
n1 = strdup(needle);
strlow(h1);
strlow(n1);
result = strstr(h1,n1);
if (result) {
rv = abs(h1 - result);
free(h1);
free(n1);
return haystack + rv;
} else {
free(h1);
free(n1);
return NULL;
}
return NULL;
}
char *n_range(char *str, int a, int b) {
char buffer[2048]= {0};
int i;
if ( b > (signed)strlen(str) || a > b )
return strdup("");
for ( i = a ; i < b ; i++ ) {
buffer[i - a] = str[i];
}
buffer[i] = 0;
return strdup(buffer);
}
list<string> *complete(list<string> &thelist, string &match, int ccase = 0, int stonly = 0) {
list<string> *lstst; // List containing strings from thelist which contain the substring match.
list<string> *lstok; // List containing strings from thelist which have match at the start of the string.
string *strptr;
string blah;
char *pos;
char *temp;
char *mat;
mat = strdup(match.c_str());
if (!ccase) strlow(mat);
lstok = new list<string>;
lstst = new list<string>;
thelist.init_trav();
while ((strptr=thelist.trav())) {
temp = strdup(strptr->c_str());
if (!ccase) strlow(temp);
if ((pos=strstr(temp, mat))) {
pos = (char*) (temp - pos);
blah = *strptr;
if (!pos) {
lstst->insert_start(blah);
} else {
lstok->insert_start(blah);
}
}
delete temp;
}
delete mat;
if (lstst->getsize() || stonly ) {
delete lstok;
return lstst;
} else {
delete lstst;
return lstok;
}
return NULL;
}
string expandmatch(list<string> &thelist, const char *thesub, int ccase = 0, int stonly = 0) {
char *tmpfull = 0;
char *ptr = 0;
char *strtmp = 0;
char *sub = 0;
char *newsub = 0;
int lentw, lensub, i;
list<string> *tmplist;
string stringtmp;
string max;
char *testword = 0;
char *orig = 0;
if (thelist.getsize() == 0) {
max = thesub;
return max;
}
thelist.init_trav();
testword = strdup(thelist.trav()->c_str());
if (thelist.getsize() == 1) {
max = testword;
} else {
orig = strdup(testword);
sub = strdup(thesub);
if (!ccase) strlow(sub);
if (!ccase) strlow(testword);
lentw = strlen(testword);
lensub = strlen(sub);
max = sub;
strtmp = new char[lentw+1];
tmpfull = testword;
while (*tmpfull) {
ptr = tmpfull = strstrnc(tmpfull,sub);
if (tmpfull != testword && tmpfull != NULL) {
i = 1;
while((ptr - i + 1) != testword) {
strncpy(strtmp,orig+abs(testword-(ptr-i)),i+lensub);
//strncpy(strtmp,ptr-i,i+lensub);
strtmp[lensub+i]=0;
stringtmp = strtmp;
tmplist = complete(thelist, stringtmp, ccase, stonly);
if (thelist.getsize() == tmplist->getsize()) {
max = stringtmp;
}
delete tmplist;
i++;
}
}
if (!tmpfull) break;
tmpfull++;
}
newsub = strdup(max.c_str());
lensub = strlen(newsub);
tmpfull = testword;
while (*tmpfull) {
ptr = tmpfull = strstrnc(tmpfull,newsub);
if (tmpfull != NULL) {
i = 1;
while(*(ptr+i+lensub-1)) {
//strncpy(strtmp,ptr,i+lensub);
strncpy(strtmp,orig+abs(testword-(ptr)),i+lensub);
strtmp[i+lensub]=0;
stringtmp = strtmp;
tmplist = complete(thelist, stringtmp, ccase, stonly);
if (thelist.getsize() == tmplist->getsize()) {
max = stringtmp;
}
delete tmplist;
i++;
}
}
if (!tmpfull) break;
tmpfull++;
}
}
if (sub) free (sub);
if (strtmp) delete strtmp;
if (newsub) free(newsub);
if (testword) delete testword;
if (orig) delete orig;
return max;
}
int TT_Proc_complete(TT_PROC_OBJS) {
list<string> somelist;
string somestring;
string *strptr;
list<string> *newlst;
Tcl_Obj *listptr;
Tcl_Obj *objptr;
int n;
int lsize;
int ccase;
int stonly;
string matchstr;
Tcl_Obj **elems;
if(objc!=5) {
Tcl_SetResult(interp,"Usage: complete <list> <matchstring> <case sensitive> <startonly>",TCL_STATIC);
return TCL_ERROR;
}
if (Tcl_ListObjGetElements(interp,objv[1],&lsize, &elems)!= TCL_OK) return TCL_ERROR;
for (n=0;n<lsize;n++) {
somestring = Tcl_GetStringFromObj(elems[n],NULL);
//printf("%s\n", somestring.c_str());
somelist.insert_start(somestring);
}
if (Tcl_GetIntFromObj(interp, objv[3], &ccase) != TCL_OK) return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &stonly) != TCL_OK) return TCL_ERROR;
matchstr = Tcl_GetStringFromObj(objv[2],NULL);
//printf("%s\n", matchstr.c_str());
//printf("%d\n", ccase);
//printf("%d\n", stonly);
newlst = complete(somelist,matchstr,ccase,stonly);
newlst->init_trav();
listptr=Tcl_NewListObj(0,0);
while((strptr=newlst->trav())) {
objptr=Tcl_NewStringObj((char *) strptr->c_str(),strlen(strptr->c_str()));
if(Tcl_ListObjAppendElement(interp,listptr,objptr)==TCL_ERROR) return TCL_ERROR;
}
Tcl_SetObjResult(interp,listptr);
delete newlst;
return TCL_OK;
}
int TT_Proc_expandmatch(TT_PROC_OBJS) {
list<string> somelist;
string somestring;
string result;
Tcl_Obj *objptr;
int n;
int lsize;
int ccase;
int stonly;
string matchstr;
Tcl_Obj **elems;
if(objc!=5) {
Tcl_SetResult(interp,"Usage: expandmatch <list> <matchstring> <case sensitive> <startonly>",TCL_STATIC);
return TCL_ERROR;
}
if (Tcl_ListObjGetElements(interp,objv[1],&lsize, &elems)!= TCL_OK) return TCL_ERROR;
for (n=0;n<lsize;n++) {
somestring = Tcl_GetStringFromObj(elems[n],NULL);
//printf("%s\n", somestring.c_str());
somelist.insert_start(somestring);
}
if (Tcl_GetIntFromObj(interp, objv[3], &ccase) != TCL_OK) return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &stonly) != TCL_OK) return TCL_ERROR;
matchstr = Tcl_GetStringFromObj(objv[2],NULL);
//printf("%s\n", matchstr.c_str());
//printf("%d\n", ccase);
//printf("%d\n", stonly);
result = expandmatch(somelist,matchstr.c_str(),ccase,stonly);
objptr=Tcl_NewStringObj((char *) result.c_str(),strlen(result.c_str()));
Tcl_SetObjResult(interp,objptr);
return TCL_OK;
}
int TT_Proc_n_complete(TT_PROC_ARGS) {
char *origtext=0;
int origpos;
int rpos;
char *befortext=0;
char *aftertext=0;
char *matchtext=0;
char *retrntext=0;
static char *oldretrntext;
static int oldpos;
static int cycnum;
static char *oldorigtext;
static int oldorigpos;
int cycle =0;
int n,i,j= 0 ,len;
list<string> thelist;
list<string> *lstptr;
string str;
string rval;
string tmpstr;
string *strptr=0;
twindow window;
twindow *windowp;
tchan channel;
tchan *channelp;
tnick *nickp;
char colon[1000] = {0};
if (!strcmp(currentwindow,".main")) {
if (origtext) free(origtext);
if (aftertext) free(aftertext);
if (matchtext) free(matchtext);
if (befortext) free(befortext);
return TCL_OK;
}
if (TT_IntF(TT_ARGS,"dcc_complete")) return TCL_OK;
// Obtain the text and cursor position from the Tk widget
// in which the completion key was pressed.
origtext = strdup(TT_StrF(TT_ARGS,"%s.entry get",currentwindow));
origpos = (TT_IntF(TT_ARGS,"%s.entry index insert",currentwindow));
if (oldretrntext && !strcmp(origtext,oldretrntext) && oldpos == origpos) {
if (origtext) free(origtext);
origtext = strdup(oldorigtext);
origpos = oldorigpos;
cycle = 1;
} else {
oldorigpos = origpos;
if (oldorigtext) free(oldorigtext);
oldorigtext = strdup(origtext);
}
n = origpos;
i = origpos;
len = strlen(origtext);
while ( i < len && origtext[i] != ' ') i++;
if ( n > 0 ) {
j = n;
while ( j >= 0 && origtext[j-1] != ' ' && j > 0 ) j--;
} else j = 0;
befortext = n_range(origtext,0,j);
matchtext = n_range(origtext,j,i);
aftertext = n_range(origtext,i,len);
str = matchtext;
strcpy(window.pathname,currentwindow);
windowp = windows.find(window);
if (!strncmp(matchtext,"#",1)) {
if ( !strncmp(currentwindow,".channel",8) && strlen(matchtext) == 1) {
tmpstr = windowp->name;
thelist.insert_start(tmpstr);
} else {
windowp->server->chanlist.init_trav();
while ( (channelp = windowp->server->chanlist.trav())) {
tmpstr = channelp->name;
thelist.insert_start(tmpstr);
}
}
lstptr = complete(thelist, str, 0,1);
if (lstptr->getsize()) {
rval = expandmatch(*lstptr, str.c_str(),0,1);
}
if (lstptr->getsize() == 1) {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_postfix"));
}
} else if ( !strncmp(currentwindow,".channel",8)) {
strcpy(channel.pathname,currentwindow);
if ((channelp = windowp->server->chanlist.find(channel)) == NULL) {
if (origtext) free(origtext);
if (aftertext) free(aftertext);
if (matchtext) free(matchtext);
if (befortext) free(befortext);
return TCL_OK;
}
channelp->nicklist.init_trav();
while ( (nickp=channelp->nicklist.trav()) ) {
tmpstr = nickp->getname();
thelist.insert_start(tmpstr);
}
lstptr = complete(thelist, str, 0,0);
lstptr->init_trav();
// while (strptr=lstptr->trav()) {
//printf("%s\n", strptr->c_str());
//}
if (lstptr->getsize()) {
rval = expandmatch(*lstptr, str.c_str(),0,0);
if (lstptr->getsize() == 1) {
if ( j <=0 ) {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_seperator"));
} else {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_postfix"));
}
}
}
} else if ( !strncmp(currentwindow,".status",7)) {
tmpstr = windowp->server->getmynick();
thelist.insert_start(tmpstr);
if (str == "") str = tmpstr;
lstptr = complete(thelist, str, 0,0);
if (lstptr->getsize()) {
rval = expandmatch(*lstptr, str.c_str(),0,0);
}
if (lstptr->getsize() == 1) {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_postfix"));
}
} else if ( !strncmp(currentwindow,".chat",5)) {
tmpstr = windowp->name + 1;
if (str == "") str = tmpstr;
thelist.insert_start(tmpstr);
tmpstr = windowp->server->getmynick();
thelist.insert_start(tmpstr);
lstptr = complete(thelist, str, 0,0);
if (lstptr->getsize()) {
rval = expandmatch(*lstptr, str.c_str(),0,0);
}
if ( j <=0 && lstptr->getsize() == 1) {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_seperator"));
} else {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_postfix"));
}
} else if ( !strncmp(currentwindow,".query",6)) {
tmpstr = windowp->name;
if (str == "") str = tmpstr;
thelist.insert_start(tmpstr);
tmpstr = windowp->server->getmynick();
if (tmpstr != str) thelist.insert_start(tmpstr);
lstptr = complete(thelist, str, 0,0);
if (lstptr->getsize()) {
rval = expandmatch(*lstptr, str.c_str(),0,0);
}
if (lstptr->getsize() == 1) {
if (j <=0 ) {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_seperator"));
} else {
strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_postfix"));
}
}
} else {
fprintf(stderr,"Invalid window type encountered in completion code.\n");
exit(1);
}
rpos = strlen(rval.c_str()) + j + strlen(colon);
if (rval == "") {
rval = matchtext;
rpos = origpos;
}
retrntext = (char *) malloc (strlen(befortext) + strlen(rval.c_str()) + strlen(aftertext) + strlen(colon) + 10);
rpos = strlen(rval.c_str()) + j + strlen(colon);
if (cycle && lstptr->getsize() > 0 && TT_Int(TT_ARGS,"set ::dynamic::nick_complete_cycle") == 1) {
if (cycnum >= lstptr->getsize()) cycnum = 0;
lstptr->init_trav();
for (int i = 0; i <= cycnum; i++) {
strptr = lstptr->trav();
}
if(cycnum<0) {
fprintf(stderr,"cycnum is less than 0 in completion code.\n");
exit(1);
}
rval = strptr->c_str();
cycnum++;
if ( j <=0 && strncmp(rval.c_str(),"#",1)) strcpy(colon,TT_Str(TT_ARGS,"set ::dynamic::nick_complete_seperator"));
if (retrntext) free(retrntext);
retrntext = (char *) malloc (strlen(befortext) + strlen(rval.c_str()) + strlen(aftertext) + strlen(colon) + 10);
rpos = strlen(rval.c_str()) + j + strlen(colon);
}
strcpy(retrntext,befortext);
strcat(retrntext,rval.c_str());
strcat(retrntext,colon);
strcat(retrntext,aftertext);
if (oldretrntext) free(oldretrntext);
oldretrntext = strdup(retrntext);
oldpos = rpos;
TT_EvalF(TT_ARGS,"%s.entry delete 0 end",currentwindow);
TT_EvalF(TT_ARGS,"%s.entry insert 0 %q",currentwindow, retrntext);
TT_EvalF(TT_ARGS,"%s.entry icursor %d",currentwindow, rpos);
if (lstptr) free(lstptr);
if (aftertext) free(aftertext);
if (origtext) free(origtext);
if (matchtext) free(matchtext);
if (befortext) free(befortext);
if (retrntext) free(retrntext);
return TCL_OK;
}
int TT_Proc_getpwents(TT_PROC_OBJS) {
char *field;
Tcl_Obj *listptr;
Tcl_Obj *objptr;
string *strptr;
string temp;
list<string> *newlst;
struct passwd *pwents;
if(objc!=2) {
Tcl_SetResult(interp,"Usage: getpwents <field>",TCL_STATIC);
return TCL_ERROR;
}
if (!(field = strdup(Tcl_GetStringFromObj(objv[1],NULL)))) return TCL_ERROR;
if (strcmp(field, "pw_name") && strcmp(field, "pw_passwd") && strcmp(field, "pw_uid") && strcmp(field, "pw_gid") && strcmp(field, "pw_gecos") && strcmp(field, "pw_dir") && strcmp(field, "pw_shell")) {
Tcl_SetResult(interp,"Error: field must be one of: pw_name, pw_passwd, pw_uid, pw_gid, pw_dir, pw_shell, pw_gecos",TCL_STATIC);
return TCL_ERROR;
}
newlst = new list<string>;
setpwent();
while ((pwents = getpwent())) {
temp = pwents->pw_name;
newlst->insert_start(temp);
}
endpwent();
newlst->init_trav();
listptr=Tcl_NewListObj(0,0);
while((strptr=newlst->trav())) {
objptr=Tcl_NewStringObj((char *) strptr->c_str(),strlen(strptr->c_str()));
if(Tcl_ListObjAppendElement(interp,listptr,objptr)==TCL_ERROR) return TCL_ERROR;
}
Tcl_SetObjResult(interp,listptr);
delete newlst;
return TCL_OK;
}
syntax highlighted by Code2HTML, v. 0.9.1