Blame


1 b330c942 2005-10-31 devnull #include <u.h>
2 b330c942 2005-10-31 devnull #include <libc.h>
3 b330c942 2005-10-31 devnull #include <draw.h>
4 b330c942 2005-10-31 devnull #include <plumb.h>
5 b330c942 2005-10-31 devnull #include <regexp.h>
6 b330c942 2005-10-31 devnull #include <bio.h>
7 b330c942 2005-10-31 devnull #include <9pclient.h>
8 b330c942 2005-10-31 devnull #include "faces.h"
9 b330c942 2005-10-31 devnull
10 b330c942 2005-10-31 devnull enum /* number of deleted faces to cache */
11 b330c942 2005-10-31 devnull {
12 cbeb0b26 2006-04-01 devnull Nsave = 20
13 b330c942 2005-10-31 devnull };
14 b330c942 2005-10-31 devnull
15 b330c942 2005-10-31 devnull static Facefile *facefiles;
16 b330c942 2005-10-31 devnull static int nsaved;
17 b330c942 2005-10-31 devnull static char *facedom;
18 00d75e0e 2006-02-11 devnull static char *libface;
19 00d75e0e 2006-02-11 devnull static char *homeface;
20 b330c942 2005-10-31 devnull
21 b330c942 2005-10-31 devnull /*
22 b330c942 2005-10-31 devnull * Loading the files is slow enough on a dial-up line to be worth this trouble
23 b330c942 2005-10-31 devnull */
24 b330c942 2005-10-31 devnull typedef struct Readcache Readcache;
25 b330c942 2005-10-31 devnull struct Readcache {
26 b330c942 2005-10-31 devnull char *file;
27 b330c942 2005-10-31 devnull char *data;
28 b330c942 2005-10-31 devnull long mtime;
29 b330c942 2005-10-31 devnull long rdtime;
30 b330c942 2005-10-31 devnull Readcache *next;
31 b330c942 2005-10-31 devnull };
32 b330c942 2005-10-31 devnull
33 b330c942 2005-10-31 devnull static Readcache *rcache;
34 b330c942 2005-10-31 devnull
35 b330c942 2005-10-31 devnull ulong
36 b330c942 2005-10-31 devnull dirlen(char *s)
37 b330c942 2005-10-31 devnull {
38 b330c942 2005-10-31 devnull Dir *d;
39 b330c942 2005-10-31 devnull ulong len;
40 b330c942 2005-10-31 devnull
41 b330c942 2005-10-31 devnull d = dirstat(s);
42 b330c942 2005-10-31 devnull if(d == nil)
43 b330c942 2005-10-31 devnull return 0;
44 b330c942 2005-10-31 devnull len = d->length;
45 b330c942 2005-10-31 devnull free(d);
46 b330c942 2005-10-31 devnull return len;
47 b330c942 2005-10-31 devnull }
48 b330c942 2005-10-31 devnull
49 b330c942 2005-10-31 devnull ulong
50 b330c942 2005-10-31 devnull fsdirlen(CFsys *fs,char *s)
51 b330c942 2005-10-31 devnull {
52 b330c942 2005-10-31 devnull Dir *d;
53 b330c942 2005-10-31 devnull ulong len;
54 b330c942 2005-10-31 devnull
55 b330c942 2005-10-31 devnull d = fsdirstat(fs,s);
56 b330c942 2005-10-31 devnull if(d == nil)
57 b330c942 2005-10-31 devnull return 0;
58 b330c942 2005-10-31 devnull len = d->length;
59 b330c942 2005-10-31 devnull free(d);
60 b330c942 2005-10-31 devnull return len;
61 b330c942 2005-10-31 devnull }
62 b330c942 2005-10-31 devnull
63 b330c942 2005-10-31 devnull ulong
64 b330c942 2005-10-31 devnull dirmtime(char *s)
65 b330c942 2005-10-31 devnull {
66 b330c942 2005-10-31 devnull Dir *d;
67 b330c942 2005-10-31 devnull ulong t;
68 b330c942 2005-10-31 devnull
69 b330c942 2005-10-31 devnull d = dirstat(s);
70 b330c942 2005-10-31 devnull if(d == nil)
71 b330c942 2005-10-31 devnull return 0;
72 b330c942 2005-10-31 devnull t = d->mtime;
73 b330c942 2005-10-31 devnull free(d);
74 b330c942 2005-10-31 devnull return t;
75 b330c942 2005-10-31 devnull }
76 b330c942 2005-10-31 devnull
77 b330c942 2005-10-31 devnull static char*
78 b330c942 2005-10-31 devnull doreadfile(char *s)
79 b330c942 2005-10-31 devnull {
80 b330c942 2005-10-31 devnull char *p;
81 b330c942 2005-10-31 devnull int fd, n;
82 b330c942 2005-10-31 devnull ulong len;
83 b330c942 2005-10-31 devnull
84 b330c942 2005-10-31 devnull len = dirlen(s);
85 b330c942 2005-10-31 devnull if(len == 0)
86 b330c942 2005-10-31 devnull return nil;
87 b330c942 2005-10-31 devnull
88 b330c942 2005-10-31 devnull p = malloc(len+1);
89 b330c942 2005-10-31 devnull if(p == nil)
90 b330c942 2005-10-31 devnull return nil;
91 b330c942 2005-10-31 devnull
92 b330c942 2005-10-31 devnull if((fd = open(s, OREAD)) < 0
93 b330c942 2005-10-31 devnull || (n = readn(fd, p, len)) < 0) {
94 b330c942 2005-10-31 devnull close(fd);
95 b330c942 2005-10-31 devnull free(p);
96 b330c942 2005-10-31 devnull return nil;
97 b330c942 2005-10-31 devnull }
98 b330c942 2005-10-31 devnull
99 b330c942 2005-10-31 devnull p[n] = '\0';
100 b330c942 2005-10-31 devnull return p;
101 b330c942 2005-10-31 devnull }
102 b330c942 2005-10-31 devnull
103 b330c942 2005-10-31 devnull static char*
104 b330c942 2005-10-31 devnull readfile(char *s)
105 b330c942 2005-10-31 devnull {
106 b330c942 2005-10-31 devnull Readcache *r, **l;
107 b330c942 2005-10-31 devnull char *p;
108 b330c942 2005-10-31 devnull ulong mtime;
109 b330c942 2005-10-31 devnull
110 b330c942 2005-10-31 devnull for(l=&rcache, r=*l; r; l=&r->next, r=*l) {
111 b330c942 2005-10-31 devnull if(strcmp(r->file, s) != 0)
112 b330c942 2005-10-31 devnull continue;
113 b330c942 2005-10-31 devnull
114 b330c942 2005-10-31 devnull /*
115 b330c942 2005-10-31 devnull * if it's less than 30 seconds since we read it, or it
116 b330c942 2005-10-31 devnull * hasn't changed, send back our copy
117 b330c942 2005-10-31 devnull */
118 b330c942 2005-10-31 devnull if(time(0) - r->rdtime < 30)
119 b330c942 2005-10-31 devnull return strdup(r->data);
120 b330c942 2005-10-31 devnull if(dirmtime(s) == r->mtime) {
121 b330c942 2005-10-31 devnull r->rdtime = time(0);
122 b330c942 2005-10-31 devnull return strdup(r->data);
123 b330c942 2005-10-31 devnull }
124 b330c942 2005-10-31 devnull
125 b330c942 2005-10-31 devnull /* out of date, remove this and fall out of loop */
126 b330c942 2005-10-31 devnull *l = r->next;
127 b330c942 2005-10-31 devnull free(r->file);
128 b330c942 2005-10-31 devnull free(r->data);
129 b330c942 2005-10-31 devnull free(r);
130 b330c942 2005-10-31 devnull break;
131 b330c942 2005-10-31 devnull }
132 b330c942 2005-10-31 devnull
133 b330c942 2005-10-31 devnull /* add to cache */
134 b330c942 2005-10-31 devnull mtime = dirmtime(s);
135 b330c942 2005-10-31 devnull if(mtime == 0)
136 b330c942 2005-10-31 devnull return nil;
137 b330c942 2005-10-31 devnull
138 b330c942 2005-10-31 devnull if((p = doreadfile(s)) == nil)
139 b330c942 2005-10-31 devnull return nil;
140 b330c942 2005-10-31 devnull
141 b330c942 2005-10-31 devnull r = malloc(sizeof(*r));
142 b330c942 2005-10-31 devnull if(r == nil)
143 b330c942 2005-10-31 devnull return nil;
144 b330c942 2005-10-31 devnull r->mtime = mtime;
145 b330c942 2005-10-31 devnull r->file = estrdup(s);
146 b330c942 2005-10-31 devnull r->data = p;
147 b330c942 2005-10-31 devnull r->rdtime = time(0);
148 b330c942 2005-10-31 devnull r->next = rcache;
149 b330c942 2005-10-31 devnull rcache = r;
150 b330c942 2005-10-31 devnull return strdup(r->data);
151 b330c942 2005-10-31 devnull }
152 b330c942 2005-10-31 devnull
153 b330c942 2005-10-31 devnull static char*
154 00d75e0e 2006-02-11 devnull translatedomain(char *dom, char *list)
155 b330c942 2005-10-31 devnull {
156 b330c942 2005-10-31 devnull static char buf[200];
157 b330c942 2005-10-31 devnull char *p, *ep, *q, *nextp, *file;
158 b330c942 2005-10-31 devnull char *bbuf, *ebuf;
159 b330c942 2005-10-31 devnull Reprog *exp;
160 b330c942 2005-10-31 devnull
161 b330c942 2005-10-31 devnull if(dom == nil || *dom == 0)
162 b330c942 2005-10-31 devnull return nil;
163 b330c942 2005-10-31 devnull
164 00d75e0e 2006-02-11 devnull if(list == nil || (file = readfile(list)) == nil)
165 b330c942 2005-10-31 devnull return dom;
166 b330c942 2005-10-31 devnull
167 b330c942 2005-10-31 devnull for(p=file; p; p=nextp) {
168 b330c942 2005-10-31 devnull if(nextp = strchr(p, '\n'))
169 b330c942 2005-10-31 devnull *nextp++ = '\0';
170 b330c942 2005-10-31 devnull
171 b330c942 2005-10-31 devnull if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2)
172 b330c942 2005-10-31 devnull continue;
173 b330c942 2005-10-31 devnull
174 b330c942 2005-10-31 devnull bbuf = buf+1;
175 b330c942 2005-10-31 devnull ebuf = buf+(1+(q-p));
176 b330c942 2005-10-31 devnull strncpy(bbuf, p, ebuf-bbuf);
177 b330c942 2005-10-31 devnull *ebuf = 0;
178 b330c942 2005-10-31 devnull if(*bbuf != '^')
179 b330c942 2005-10-31 devnull *--bbuf = '^';
180 b330c942 2005-10-31 devnull if(ebuf[-1] != '$') {
181 b330c942 2005-10-31 devnull *ebuf++ = '$';
182 b330c942 2005-10-31 devnull *ebuf = 0;
183 b330c942 2005-10-31 devnull }
184 b330c942 2005-10-31 devnull
185 b330c942 2005-10-31 devnull if((exp = regcomp(bbuf)) == nil){
186 b330c942 2005-10-31 devnull fprint(2, "bad regexp in machinelist: %s\n", bbuf);
187 b330c942 2005-10-31 devnull killall("regexp");
188 b330c942 2005-10-31 devnull }
189 b330c942 2005-10-31 devnull
190 b330c942 2005-10-31 devnull if(regexec(exp, dom, 0, 0)){
191 b330c942 2005-10-31 devnull free(exp);
192 b330c942 2005-10-31 devnull ep = p+strlen(p);
193 b330c942 2005-10-31 devnull q += strspn(q, " \t");
194 b330c942 2005-10-31 devnull if(ep-q+2 > sizeof buf) {
195 b330c942 2005-10-31 devnull fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q);
196 b330c942 2005-10-31 devnull exits("bad big replacement");
197 b330c942 2005-10-31 devnull }
198 b330c942 2005-10-31 devnull strncpy(buf, q, ep-q);
199 b330c942 2005-10-31 devnull ebuf = buf+(ep-q);
200 b330c942 2005-10-31 devnull *ebuf = 0;
201 b330c942 2005-10-31 devnull while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t'))
202 b330c942 2005-10-31 devnull *--ebuf = 0;
203 b330c942 2005-10-31 devnull free(file);
204 b330c942 2005-10-31 devnull return buf;
205 b330c942 2005-10-31 devnull }
206 b330c942 2005-10-31 devnull free(exp);
207 b330c942 2005-10-31 devnull }
208 b330c942 2005-10-31 devnull free(file);
209 b330c942 2005-10-31 devnull
210 b330c942 2005-10-31 devnull return dom;
211 b330c942 2005-10-31 devnull }
212 b330c942 2005-10-31 devnull
213 b330c942 2005-10-31 devnull static char*
214 00d75e0e 2006-02-11 devnull tryfindpicture(char *dom, char *user, char *dir, char *dict)
215 b330c942 2005-10-31 devnull {
216 00d75e0e 2006-02-11 devnull static char buf[1024];
217 00d75e0e 2006-02-11 devnull char *file, *p, *nextp, *q;
218 00d75e0e 2006-02-11 devnull
219 00d75e0e 2006-02-11 devnull if((file = readfile(dict)) == nil)
220 a5ba8a59 2005-11-12 devnull return nil;
221 a5ba8a59 2005-11-12 devnull
222 b330c942 2005-10-31 devnull snprint(buf, sizeof buf, "%s/%s", dom, user);
223 b330c942 2005-10-31 devnull
224 00d75e0e 2006-02-11 devnull for(p=file; p; p=nextp){
225 b330c942 2005-10-31 devnull if(nextp = strchr(p, '\n'))
226 b330c942 2005-10-31 devnull *nextp++ = '\0';
227 b330c942 2005-10-31 devnull
228 b330c942 2005-10-31 devnull if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
229 b330c942 2005-10-31 devnull continue;
230 b330c942 2005-10-31 devnull *q++ = 0;
231 b330c942 2005-10-31 devnull
232 00d75e0e 2006-02-11 devnull if(strcmp(buf, p) == 0){
233 b330c942 2005-10-31 devnull q += strspn(q, " \t");
234 00d75e0e 2006-02-11 devnull snprint(buf, sizeof buf, "%s/%s", dir, q);
235 00d75e0e 2006-02-11 devnull q = buf+strlen(buf);
236 b330c942 2005-10-31 devnull while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
237 b330c942 2005-10-31 devnull *--q = 0;
238 b330c942 2005-10-31 devnull free(file);
239 00d75e0e 2006-02-11 devnull return estrdup(buf);
240 b330c942 2005-10-31 devnull }
241 b330c942 2005-10-31 devnull }
242 b330c942 2005-10-31 devnull free(file);
243 00d75e0e 2006-02-11 devnull return nil;
244 b330c942 2005-10-31 devnull }
245 b330c942 2005-10-31 devnull
246 b330c942 2005-10-31 devnull static char*
247 00d75e0e 2006-02-11 devnull estrstrdup(char *a, char *b)
248 b330c942 2005-10-31 devnull {
249 00d75e0e 2006-02-11 devnull char *t;
250 00d75e0e 2006-02-11 devnull
251 00d75e0e 2006-02-11 devnull t = emalloc(strlen(a)+strlen(b)+1);
252 00d75e0e 2006-02-11 devnull strcpy(t, a);
253 00d75e0e 2006-02-11 devnull strcat(t, b);
254 00d75e0e 2006-02-11 devnull return t;
255 b330c942 2005-10-31 devnull }
256 b330c942 2005-10-31 devnull
257 b330c942 2005-10-31 devnull static char*
258 00d75e0e 2006-02-11 devnull tryfindfiledir(char *dom, char *user, char *dir)
259 b330c942 2005-10-31 devnull {
260 2eef1fa3 2006-02-14 devnull char *dict, *ndir, *x, *odom;
261 00d75e0e 2006-02-11 devnull int fd;
262 00d75e0e 2006-02-11 devnull int i, n;
263 00d75e0e 2006-02-11 devnull Dir *d;
264 00d75e0e 2006-02-11 devnull
265 00d75e0e 2006-02-11 devnull /*
266 00d75e0e 2006-02-11 devnull * If this directory has a .machinelist, use it.
267 00d75e0e 2006-02-11 devnull */
268 00d75e0e 2006-02-11 devnull x = estrstrdup(dir, "/.machinelist");
269 00d75e0e 2006-02-11 devnull dom = estrdup(translatedomain(dom, x));
270 00d75e0e 2006-02-11 devnull free(x);
271 00d75e0e 2006-02-11 devnull /*
272 00d75e0e 2006-02-11 devnull * If this directory has a .dict, use it.
273 00d75e0e 2006-02-11 devnull */
274 00d75e0e 2006-02-11 devnull dict = estrstrdup(dir, "/.dict");
275 00d75e0e 2006-02-11 devnull if(access(dict, AEXIST) >= 0){
276 00d75e0e 2006-02-11 devnull x = tryfindpicture(dom, user, dir, dict);
277 00d75e0e 2006-02-11 devnull free(dict);
278 00d75e0e 2006-02-11 devnull free(dom);
279 00d75e0e 2006-02-11 devnull return x;
280 00d75e0e 2006-02-11 devnull }
281 00d75e0e 2006-02-11 devnull free(dict);
282 00d75e0e 2006-02-11 devnull
283 00d75e0e 2006-02-11 devnull /*
284 00d75e0e 2006-02-11 devnull * If not, recurse into subdirectories.
285 00d75e0e 2006-02-11 devnull * Ignore 48x48xN directories for now.
286 00d75e0e 2006-02-11 devnull */
287 00d75e0e 2006-02-11 devnull if((fd = open(dir, OREAD)) < 0)
288 00d75e0e 2006-02-11 devnull return nil;
289 00d75e0e 2006-02-11 devnull while((n = dirread(fd, &d)) > 0){
290 00d75e0e 2006-02-11 devnull for(i=0; i<n; i++){
291 00d75e0e 2006-02-11 devnull if((d[i].mode&DMDIR)&& strncmp(d[i].name, "48x48x", 6) != 0){
292 00d75e0e 2006-02-11 devnull ndir = emalloc(strlen(dir)+1+strlen(d[i].name)+1);
293 00d75e0e 2006-02-11 devnull strcpy(ndir, dir);
294 00d75e0e 2006-02-11 devnull strcat(ndir, "/");
295 00d75e0e 2006-02-11 devnull strcat(ndir, d[i].name);
296 00d75e0e 2006-02-11 devnull if((x = tryfindfiledir(dom, user, ndir)) != nil){
297 00d75e0e 2006-02-11 devnull free(ndir);
298 00d75e0e 2006-02-11 devnull free(d);
299 00d75e0e 2006-02-11 devnull close(fd);
300 00d75e0e 2006-02-11 devnull free(dom);
301 00d75e0e 2006-02-11 devnull return x;
302 00d75e0e 2006-02-11 devnull }
303 00d75e0e 2006-02-11 devnull }
304 00d75e0e 2006-02-11 devnull }
305 00d75e0e 2006-02-11 devnull free(d);
306 00d75e0e 2006-02-11 devnull }
307 00d75e0e 2006-02-11 devnull close(fd);
308 00d75e0e 2006-02-11 devnull
309 00d75e0e 2006-02-11 devnull /*
310 00d75e0e 2006-02-11 devnull * Handle 48x48xN directories in the right order.
311 00d75e0e 2006-02-11 devnull */
312 00d75e0e 2006-02-11 devnull ndir = estrstrdup(dir, "/48x48x8");
313 00d75e0e 2006-02-11 devnull for(i=8; i>0; i>>=1){
314 00d75e0e 2006-02-11 devnull ndir[strlen(ndir)-1] = i+'0';
315 00d75e0e 2006-02-11 devnull if(access(ndir, AEXIST) >= 0 && (x = tryfindfiledir(dom, user, ndir)) != nil){
316 00d75e0e 2006-02-11 devnull free(ndir);
317 00d75e0e 2006-02-11 devnull free(dom);
318 00d75e0e 2006-02-11 devnull return x;
319 00d75e0e 2006-02-11 devnull }
320 00d75e0e 2006-02-11 devnull }
321 00d75e0e 2006-02-11 devnull free(ndir);
322 00d75e0e 2006-02-11 devnull free(dom);
323 00d75e0e 2006-02-11 devnull return nil;
324 b330c942 2005-10-31 devnull }
325 b330c942 2005-10-31 devnull
326 b330c942 2005-10-31 devnull static char*
327 00d75e0e 2006-02-11 devnull tryfindfile(char *dom, char *user)
328 b330c942 2005-10-31 devnull {
329 00d75e0e 2006-02-11 devnull char *p;
330 b330c942 2005-10-31 devnull
331 00d75e0e 2006-02-11 devnull while(dom && *dom){
332 00d75e0e 2006-02-11 devnull if(homeface && (p = tryfindfiledir(dom, user, homeface)) != nil)
333 00d75e0e 2006-02-11 devnull return p;
334 00d75e0e 2006-02-11 devnull if((p = tryfindfiledir(dom, user, libface)) != nil)
335 00d75e0e 2006-02-11 devnull return p;
336 00d75e0e 2006-02-11 devnull if((dom = strchr(dom, '.')) == nil)
337 b330c942 2005-10-31 devnull break;
338 00d75e0e 2006-02-11 devnull dom++;
339 b330c942 2005-10-31 devnull }
340 b330c942 2005-10-31 devnull return nil;
341 b330c942 2005-10-31 devnull }
342 b330c942 2005-10-31 devnull
343 b330c942 2005-10-31 devnull char*
344 b330c942 2005-10-31 devnull findfile(Face *f, char *dom, char *user)
345 b330c942 2005-10-31 devnull {
346 b330c942 2005-10-31 devnull char *p;
347 b330c942 2005-10-31 devnull
348 b330c942 2005-10-31 devnull if(facedom == nil){
349 b330c942 2005-10-31 devnull facedom = getenv("facedom");
350 b330c942 2005-10-31 devnull if(facedom == nil)
351 b330c942 2005-10-31 devnull facedom = DEFAULT;
352 b330c942 2005-10-31 devnull }
353 00d75e0e 2006-02-11 devnull if(libface == nil)
354 00d75e0e 2006-02-11 devnull libface = unsharp("#9/face");
355 00d75e0e 2006-02-11 devnull if(homeface == nil)
356 00d75e0e 2006-02-11 devnull homeface = smprint("%s/lib/face", getenv("HOME"));
357 b330c942 2005-10-31 devnull
358 b330c942 2005-10-31 devnull if(dom == nil)
359 b330c942 2005-10-31 devnull dom = facedom;
360 b330c942 2005-10-31 devnull
361 b330c942 2005-10-31 devnull f->unknown = 0;
362 00d75e0e 2006-02-11 devnull if((p = tryfindfile(dom, user)) != nil)
363 b330c942 2005-10-31 devnull return p;
364 b330c942 2005-10-31 devnull f->unknown = 1;
365 00d75e0e 2006-02-11 devnull p = tryfindfile(dom, "unknown");
366 00d75e0e 2006-02-11 devnull if(p != nil || strcmp(dom, facedom) == 0)
367 b330c942 2005-10-31 devnull return p;
368 00d75e0e 2006-02-11 devnull return tryfindfile("unknown", "unknown");
369 b330c942 2005-10-31 devnull }
370 b330c942 2005-10-31 devnull
371 b330c942 2005-10-31 devnull static
372 b330c942 2005-10-31 devnull void
373 b330c942 2005-10-31 devnull clearsaved(void)
374 b330c942 2005-10-31 devnull {
375 b330c942 2005-10-31 devnull Facefile *f, *next, **lf;
376 b330c942 2005-10-31 devnull
377 b330c942 2005-10-31 devnull lf = &facefiles;
378 b330c942 2005-10-31 devnull for(f=facefiles; f!=nil; f=next){
379 b330c942 2005-10-31 devnull next = f->next;
380 b330c942 2005-10-31 devnull if(f->ref > 0){
381 b330c942 2005-10-31 devnull *lf = f;
382 b330c942 2005-10-31 devnull lf = &(f->next);
383 b330c942 2005-10-31 devnull continue;
384 b330c942 2005-10-31 devnull }
385 b330c942 2005-10-31 devnull if(f->image != display->black && f->image != display->white)
386 b330c942 2005-10-31 devnull freeimage(f->image);
387 b330c942 2005-10-31 devnull free(f->file);
388 b330c942 2005-10-31 devnull free(f);
389 b330c942 2005-10-31 devnull }
390 b330c942 2005-10-31 devnull *lf = nil;
391 b330c942 2005-10-31 devnull nsaved = 0;
392 b330c942 2005-10-31 devnull }
393 b330c942 2005-10-31 devnull
394 b330c942 2005-10-31 devnull void
395 b330c942 2005-10-31 devnull freefacefile(Facefile *f)
396 b330c942 2005-10-31 devnull {
397 b330c942 2005-10-31 devnull if(f==nil || f->ref-->1)
398 b330c942 2005-10-31 devnull return;
399 b330c942 2005-10-31 devnull if(++nsaved > Nsave)
400 b330c942 2005-10-31 devnull clearsaved();
401 b330c942 2005-10-31 devnull }
402 b330c942 2005-10-31 devnull
403 b330c942 2005-10-31 devnull static Image*
404 b330c942 2005-10-31 devnull myallocimage(ulong chan)
405 b330c942 2005-10-31 devnull {
406 b330c942 2005-10-31 devnull Image *img;
407 b330c942 2005-10-31 devnull img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
408 b330c942 2005-10-31 devnull if(img == nil){
409 b330c942 2005-10-31 devnull clearsaved();
410 b330c942 2005-10-31 devnull img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
411 b330c942 2005-10-31 devnull if(img == nil)
412 b330c942 2005-10-31 devnull return nil;
413 b330c942 2005-10-31 devnull }
414 b330c942 2005-10-31 devnull return img;
415 b330c942 2005-10-31 devnull }
416 b330c942 2005-10-31 devnull
417 b330c942 2005-10-31 devnull
418 b330c942 2005-10-31 devnull static Image*
419 b330c942 2005-10-31 devnull readbit(int fd, ulong chan)
420 b330c942 2005-10-31 devnull {
421 b330c942 2005-10-31 devnull char buf[4096], hx[4], *p;
422 b330c942 2005-10-31 devnull uchar data[Facesize*Facesize]; /* more than enough */
423 b330c942 2005-10-31 devnull int nhx, i, n, ndata, nbit;
424 b330c942 2005-10-31 devnull Image *img;
425 b330c942 2005-10-31 devnull
426 b330c942 2005-10-31 devnull n = readn(fd, buf, sizeof buf);
427 b330c942 2005-10-31 devnull if(n <= 0)
428 b330c942 2005-10-31 devnull return nil;
429 b330c942 2005-10-31 devnull if(n >= sizeof buf)
430 b330c942 2005-10-31 devnull n = sizeof(buf)-1;
431 b330c942 2005-10-31 devnull buf[n] = '\0';
432 b330c942 2005-10-31 devnull
433 b330c942 2005-10-31 devnull n = 0;
434 b330c942 2005-10-31 devnull nhx = 0;
435 b330c942 2005-10-31 devnull nbit = chantodepth(chan);
436 b330c942 2005-10-31 devnull ndata = (Facesize*Facesize*nbit)/8;
437 b330c942 2005-10-31 devnull p = buf;
438 b330c942 2005-10-31 devnull while(n < ndata) {
439 b330c942 2005-10-31 devnull p = strpbrk(p+1, "0123456789abcdefABCDEF");
440 b330c942 2005-10-31 devnull if(p == nil)
441 b330c942 2005-10-31 devnull break;
442 b330c942 2005-10-31 devnull if(p[0] == '0' && p[1] == 'x')
443 b330c942 2005-10-31 devnull continue;
444 b330c942 2005-10-31 devnull
445 b330c942 2005-10-31 devnull hx[nhx] = *p;
446 b330c942 2005-10-31 devnull if(++nhx == 2) {
447 b330c942 2005-10-31 devnull hx[nhx] = 0;
448 b330c942 2005-10-31 devnull i = strtoul(hx, 0, 16);
449 b330c942 2005-10-31 devnull data[n++] = i;
450 b330c942 2005-10-31 devnull nhx = 0;
451 b330c942 2005-10-31 devnull }
452 b330c942 2005-10-31 devnull }
453 b330c942 2005-10-31 devnull if(n < ndata)
454 b330c942 2005-10-31 devnull return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888);
455 b330c942 2005-10-31 devnull
456 b330c942 2005-10-31 devnull img = myallocimage(chan);
457 b330c942 2005-10-31 devnull if(img == nil)
458 b330c942 2005-10-31 devnull return nil;
459 b330c942 2005-10-31 devnull loadimage(img, img->r, data, ndata);
460 b330c942 2005-10-31 devnull return img;
461 b330c942 2005-10-31 devnull }
462 b330c942 2005-10-31 devnull
463 b330c942 2005-10-31 devnull static Facefile*
464 b330c942 2005-10-31 devnull readface(char *fn)
465 b330c942 2005-10-31 devnull {
466 b330c942 2005-10-31 devnull int x, y, fd;
467 b330c942 2005-10-31 devnull uchar bits;
468 b330c942 2005-10-31 devnull uchar *p;
469 b330c942 2005-10-31 devnull Image *mask;
470 b330c942 2005-10-31 devnull Image *face;
471 b330c942 2005-10-31 devnull char buf[16];
472 b330c942 2005-10-31 devnull uchar data[Facesize*Facesize];
473 b330c942 2005-10-31 devnull uchar mdata[(Facesize*Facesize)/8];
474 b330c942 2005-10-31 devnull Facefile *f;
475 b330c942 2005-10-31 devnull Dir *d;
476 b330c942 2005-10-31 devnull
477 b330c942 2005-10-31 devnull for(f=facefiles; f!=nil; f=f->next){
478 b330c942 2005-10-31 devnull if(strcmp(fn, f->file) == 0){
479 b330c942 2005-10-31 devnull if(f->image == nil)
480 b330c942 2005-10-31 devnull break;
481 b330c942 2005-10-31 devnull if(time(0) - f->rdtime >= 30) {
482 b330c942 2005-10-31 devnull if(dirmtime(fn) != f->mtime){
483 b330c942 2005-10-31 devnull f = nil;
484 b330c942 2005-10-31 devnull break;
485 b330c942 2005-10-31 devnull }
486 b330c942 2005-10-31 devnull f->rdtime = time(0);
487 b330c942 2005-10-31 devnull }
488 b330c942 2005-10-31 devnull f->ref++;
489 b330c942 2005-10-31 devnull return f;
490 b330c942 2005-10-31 devnull }
491 b330c942 2005-10-31 devnull }
492 b330c942 2005-10-31 devnull
493 b330c942 2005-10-31 devnull if((fd = open(fn, OREAD)) < 0)
494 b330c942 2005-10-31 devnull return nil;
495 b330c942 2005-10-31 devnull
496 b330c942 2005-10-31 devnull if(readn(fd, buf, sizeof buf) != sizeof buf){
497 b330c942 2005-10-31 devnull close(fd);
498 b330c942 2005-10-31 devnull return nil;
499 b330c942 2005-10-31 devnull }
500 b330c942 2005-10-31 devnull
501 b330c942 2005-10-31 devnull seek(fd, 0, 0);
502 b330c942 2005-10-31 devnull
503 b330c942 2005-10-31 devnull mask = nil;
504 b330c942 2005-10-31 devnull if(buf[0] == '0' && buf[1] == 'x'){
505 b330c942 2005-10-31 devnull /* greyscale faces are just masks that we draw black through! */
506 b330c942 2005-10-31 devnull if(buf[2+8] == ',') /* ldepth 1 */
507 b330c942 2005-10-31 devnull mask = readbit(fd, GREY2);
508 b330c942 2005-10-31 devnull else
509 b330c942 2005-10-31 devnull mask = readbit(fd, GREY1);
510 b330c942 2005-10-31 devnull face = display->black;
511 b330c942 2005-10-31 devnull }else{
512 b330c942 2005-10-31 devnull face = readimage(display, fd, 0);
513 b330c942 2005-10-31 devnull if(face == nil)
514 b330c942 2005-10-31 devnull goto Done;
515 b330c942 2005-10-31 devnull else if(face->chan == GREY4 || face->chan == GREY8){ /* greyscale: use inversion as mask */
516 b330c942 2005-10-31 devnull mask = myallocimage(face->chan);
517 b330c942 2005-10-31 devnull /* okay if mask is nil: that will copy the image white background and all */
518 b330c942 2005-10-31 devnull if(mask == nil)
519 b330c942 2005-10-31 devnull goto Done;
520 b330c942 2005-10-31 devnull
521 b330c942 2005-10-31 devnull /* invert greyscale image */
522 b330c942 2005-10-31 devnull draw(mask, mask->r, display->white, nil, ZP);
523 b330c942 2005-10-31 devnull gendraw(mask, mask->r, display->black, ZP, face, face->r.min);
524 b330c942 2005-10-31 devnull freeimage(face);
525 b330c942 2005-10-31 devnull face = display->black;
526 b330c942 2005-10-31 devnull }else if(face->depth == 8){ /* snarf the bytes back and do a fill. */
527 b330c942 2005-10-31 devnull mask = myallocimage(GREY1);
528 b330c942 2005-10-31 devnull if(mask == nil)
529 b330c942 2005-10-31 devnull goto Done;
530 b330c942 2005-10-31 devnull if(unloadimage(face, face->r, data, Facesize*Facesize) != Facesize*Facesize){
531 b330c942 2005-10-31 devnull freeimage(mask);
532 b330c942 2005-10-31 devnull goto Done;
533 b330c942 2005-10-31 devnull }
534 b330c942 2005-10-31 devnull bits = 0;
535 b330c942 2005-10-31 devnull p = mdata;
536 b330c942 2005-10-31 devnull for(y=0; y<Facesize; y++){
537 b330c942 2005-10-31 devnull for(x=0; x<Facesize; x++){
538 b330c942 2005-10-31 devnull bits <<= 1;
539 b330c942 2005-10-31 devnull if(data[Facesize*y+x] != 0xFF)
540 b330c942 2005-10-31 devnull bits |= 1;
541 b330c942 2005-10-31 devnull if((x&7) == 7)
542 b330c942 2005-10-31 devnull *p++ = bits&0xFF;
543 b330c942 2005-10-31 devnull }
544 b330c942 2005-10-31 devnull }
545 b330c942 2005-10-31 devnull if(loadimage(mask, mask->r, mdata, sizeof mdata) != sizeof mdata){
546 b330c942 2005-10-31 devnull freeimage(mask);
547 b330c942 2005-10-31 devnull goto Done;
548 b330c942 2005-10-31 devnull }
549 b330c942 2005-10-31 devnull }
550 b330c942 2005-10-31 devnull }
551 b330c942 2005-10-31 devnull
552 b330c942 2005-10-31 devnull Done:
553 b330c942 2005-10-31 devnull /* always add at beginning of list, so updated files don't collide in cache */
554 b330c942 2005-10-31 devnull if(f == nil){
555 b330c942 2005-10-31 devnull f = emalloc(sizeof(Facefile));
556 b330c942 2005-10-31 devnull f->file = estrdup(fn);
557 b330c942 2005-10-31 devnull d = dirfstat(fd);
558 b330c942 2005-10-31 devnull if(d != nil){
559 b330c942 2005-10-31 devnull f->mtime = d->mtime;
560 b330c942 2005-10-31 devnull free(d);
561 b330c942 2005-10-31 devnull }
562 b330c942 2005-10-31 devnull f->next = facefiles;
563 b330c942 2005-10-31 devnull facefiles = f;
564 b330c942 2005-10-31 devnull }
565 b330c942 2005-10-31 devnull f->ref++;
566 b330c942 2005-10-31 devnull f->image = face;
567 b330c942 2005-10-31 devnull f->mask = mask;
568 b330c942 2005-10-31 devnull f->rdtime = time(0);
569 b330c942 2005-10-31 devnull close(fd);
570 b330c942 2005-10-31 devnull return f;
571 b330c942 2005-10-31 devnull }
572 b330c942 2005-10-31 devnull
573 b330c942 2005-10-31 devnull void
574 b330c942 2005-10-31 devnull findbit(Face *f)
575 b330c942 2005-10-31 devnull {
576 b330c942 2005-10-31 devnull char *fn;
577 b330c942 2005-10-31 devnull
578 b330c942 2005-10-31 devnull fn = findfile(f, f->str[Sdomain], f->str[Suser]);
579 b330c942 2005-10-31 devnull if(fn) {
580 b330c942 2005-10-31 devnull if(strstr(fn, "unknown"))
581 b330c942 2005-10-31 devnull f->unknown = 1;
582 b330c942 2005-10-31 devnull f->file = readface(fn);
583 b330c942 2005-10-31 devnull }
584 b330c942 2005-10-31 devnull if(f->file){
585 b330c942 2005-10-31 devnull f->bit = f->file->image;
586 b330c942 2005-10-31 devnull f->mask = f->file->mask;
587 b330c942 2005-10-31 devnull }else{
588 b330c942 2005-10-31 devnull /* if returns nil, this is still ok: draw(nil) works */
589 b330c942 2005-10-31 devnull f->bit = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DYellow);
590 b330c942 2005-10-31 devnull replclipr(f->bit, 1, Rect(0, 0, Facesize, Facesize));
591 b330c942 2005-10-31 devnull f->mask = nil;
592 b330c942 2005-10-31 devnull }
593 b330c942 2005-10-31 devnull }