Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/libcomplete/complete.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include "complete.h"
4
 
5
static int
6
longestprefixlength(char *a, char *b, int n)
7
{
8
	int i, w;
9
	Rune ra, rb;
10
 
11
	for(i=0; i<n; i+=w){
12
		w = chartorune(&ra, a);
13
		chartorune(&rb, b);
14
		if(ra != rb)
15
			break;
16
		a += w;
17
		b += w;
18
	}
19
	return i;
20
}
21
 
22
void
23
freecompletion(Completion *c)
24
{
25
	if(c){
26
		free(c->filename);
27
		free(c);
28
	}
29
}
30
 
31
static int
32
strpcmp(const void *va, const void *vb)
33
{
34
	char *a, *b;
35
 
36
	a = *(char**)va;
37
	b = *(char**)vb;
38
	return strcmp(a, b);
39
}
40
 
41
Completion*
42
complete(char *dir, char *s)
43
{
44
	long i, l, n, nfile, len, nbytes;
45
	int fd, minlen;
46
	Dir *dirp;
47
	char **name, *p;
48
	ulong* mode;
49
	Completion *c;
50
 
51
	if(strchr(s, '/') != nil){
52
		werrstr("slash character in name argument to complete()");
53
		return nil;
54
	}
55
 
56
	fd = open(dir, OREAD);
57
	if(fd < 0)
58
		return nil;
59
 
60
	n = dirreadall(fd, &dirp);
61
	if(n <= 0){
62
		close(fd);
63
		return nil;
64
	}
65
 
66
	/* find longest string, for allocation */
67
	len = 0;
68
	for(i=0; i<n; i++){
69
		l = strlen(dirp[i].name) + 1 + 1; /* +1 for /   +1 for \0 */
70
		if(l > len)
71
			len = l;
72
	}
73
 
74
	name = malloc(n*sizeof(char*));
75
	mode = malloc(n*sizeof(ulong));
76
	c = malloc(sizeof(Completion) + len);
77
	if(name == nil || mode == nil || c == nil)
78
		goto Return;
79
	memset(c, 0, sizeof(Completion));
80
 
81
	/* find the matches */
82
	len = strlen(s);
83
	nfile = 0;
84
	minlen = 1000000;
85
	for(i=0; i<n; i++)
86
		if(strncmp(s, dirp[i].name, len) == 0){
87
			name[nfile] = dirp[i].name;
88
			mode[nfile] = dirp[i].mode;
89
			if(minlen > strlen(dirp[i].name))
90
				minlen = strlen(dirp[i].name);
91
			nfile++;
92
		}
93
 
94
	if(nfile > 0) {
95
		/* report interesting results */
96
		/* trim length back to longest common initial string */
97
		for(i=1; i<nfile; i++)
98
			minlen = longestprefixlength(name[0], name[i], minlen);
99
 
100
		/* build the answer */
101
		c->complete = (nfile == 1);
102
		c->advance = c->complete || (minlen > len);
103
		c->string = (char*)(c+1);
104
		memmove(c->string, name[0]+len, minlen-len);
105
		if(c->complete)
106
			c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
107
		c->string[minlen - len] = '\0';
108
		c->nmatch = nfile;
109
	} else {
110
		/* no match, so return all possible strings */
111
		for(i=0; i<n; i++){
112
			name[i] = dirp[i].name;
113
			mode[i] = dirp[i].mode;
114
		}
115
		nfile = n;
116
		c->nmatch = 0;
117
	}
118
 
119
	/* attach list of names */
120
	nbytes = nfile * sizeof(char*);
121
	for(i=0; i<nfile; i++)
122
		nbytes += strlen(name[i]) + 1 + 1;
123
	c->filename = malloc(nbytes);
124
	if(c->filename == nil)
125
		goto Return;
126
	p = (char*)(c->filename + nfile);
127
	for(i=0; i<nfile; i++){
128
		c->filename[i] = p;
129
		strcpy(p, name[i]);
130
		p += strlen(p);
131
		if(mode[i] & DMDIR)
132
			*p++ = '/';
133
		*p++ = '\0';
134
	}
135
	c->nfile = nfile;
136
	qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
137
 
138
  Return:
139
	free(name);
140
	free(mode);
141
	free(dirp);
142
	close(fd);
143
	return c;
144
}