144 lines · 2.7 KB · C
RawDownload
#include <u.h>#include <libc.h>#include "complete.h" static intlongestprefixlength(char *a, char *b, int n){	int i, w;	Rune ra, rb; 	for(i=0; i<n; i+=w){		w = chartorune(&ra, a);		chartorune(&rb, b);		if(ra != rb)			break;		a += w;		b += w;	}	return i;} voidfreecompletion(Completion *c){	if(c){		free(c->filename);		free(c);	}} static intstrpcmp(const void *va, const void *vb){	char *a, *b; 	a = *(char**)va;	b = *(char**)vb;	return strcmp(a, b);} Completion*complete(char *dir, char *s){	long i, l, n, nfile, len, nbytes;	int fd, minlen;	Dir *dirp;	char **name, *p;	ulong* mode;	Completion *c; 	if(strchr(s, '/') != nil){		werrstr("slash character in name argument to complete()");		return nil;	} 	fd = open(dir, OREAD);	if(fd < 0)		return nil; 	n = dirreadall(fd, &dirp);	if(n <= 0){		close(fd);		return nil;	} 	/* find longest string, for allocation */	len = 0;	for(i=0; i<n; i++){		l = strlen(dirp[i].name) + 1 + 1; /* +1 for /   +1 for \0 */		if(l > len)			len = l;	} 	name = malloc(n*sizeof(char*));	mode = malloc(n*sizeof(ulong));	c = malloc(sizeof(Completion) + len);	if(name == nil || mode == nil || c == nil)		goto Return;	memset(c, 0, sizeof(Completion)); 	/* find the matches */	len = strlen(s);	nfile = 0;	minlen = 1000000;	for(i=0; i<n; i++)		if(strncmp(s, dirp[i].name, len) == 0){			name[nfile] = dirp[i].name;			mode[nfile] = dirp[i].mode;			if(minlen > strlen(dirp[i].name))				minlen = strlen(dirp[i].name);			nfile++;		} 	if(nfile > 0) {		/* report interesting results */		/* trim length back to longest common initial string */		for(i=1; i<nfile; i++)			minlen = longestprefixlength(name[0], name[i], minlen); 		/* build the answer */		c->complete = (nfile == 1);		c->advance = c->complete || (minlen > len);		c->string = (char*)(c+1);		memmove(c->string, name[0]+len, minlen-len);		if(c->complete)			c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';		c->string[minlen - len] = '\0';		c->nmatch = nfile;	} else {		/* no match, so return all possible strings */		for(i=0; i<n; i++){			name[i] = dirp[i].name;			mode[i] = dirp[i].mode;		}		nfile = n;		c->nmatch = 0;	} 	/* attach list of names */	nbytes = nfile * sizeof(char*);	for(i=0; i<nfile; i++)		nbytes += strlen(name[i]) + 1 + 1;	c->filename = malloc(nbytes);	if(c->filename == nil)		goto Return;	p = (char*)(c->filename + nfile);	for(i=0; i<nfile; i++){		c->filename[i] = p;		strcpy(p, name[i]);		p += strlen(p);		if(mode[i] & DMDIR)			*p++ = '/';		*p++ = '\0';	}	c->nfile = nfile;	qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);   Return:	free(name);	free(mode);	free(dirp);	close(fd);	return c;}