xref: /plan9/acme/bin/source/acd/acme.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
1 #include "acd.h"
2 
3 static int
iscmd(char * s,char * cmd)4 iscmd(char *s, char *cmd)
5 {
6 	int len;
7 
8 	len = strlen(cmd);
9 	return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n');
10 }
11 
12 static char*
skip(char * s,char * cmd)13 skip(char *s, char *cmd)
14 {
15 	s += strlen(cmd);
16 	while(*s==' ' || *s=='\t' || *s=='\n')
17 		s++;
18 	return s;
19 }
20 
21 //#define PLAYSTRING "/^[0-9:]+>"
22 //#define PLAYSTRINGSPACE "/^[0-9:]+> ?"
23 //#define INITSTRING "0:00> "
24 
25 #define INITSTRING "> "
26 #define PLAYSTRING "/^>"
27 #define PLAYSTRINGSPACE "/^> ?"
28 
29 /*
30  * find the playing string, leave in addr
31  * if q0, q1 are non-nil, set them to the addr of the string.
32  */
33 int
findplay(Window * w,char * s,ulong * q0,ulong * q1)34 findplay(Window *w, char *s, ulong *q0, ulong *q1)
35 {
36 	char xbuf[25];
37 	if(w->data < 0)
38 		w->data = winopenfile(w, "data");
39 
40 	if(!winsetaddr(w, "#0", 1) || !winsetaddr(w, s, 1))
41 		return 0;
42 
43 	seek(w->addr, 0, 0);
44 	if(read(w->addr, xbuf, 24) != 24)
45 		return 0;
46 
47 	xbuf[24] = 0;
48 	if(q0)
49 		*q0 = atoi(xbuf);
50 	if(q1)
51 		*q1 = atoi(xbuf+12);
52 
53 	return 1;
54 }
55 
56 /*
57  * find the playing string and replace the time
58  */
59 int
setplaytime(Window * w,char * new)60 setplaytime(Window *w, char *new)
61 {
62 	char buf[40];
63 	ulong q0, q1;
64 
65 return 1;
66 	if(!findplay(w, PLAYSTRING, &q0, &q1))
67 		return 0;
68 
69 	q1--;	/* > */
70 	sprint(buf, "#%lud,#%lud", q0, q1);
71 	DPRINT(2, "setaddr %s\n", buf);
72 	if(!winsetaddr(w, buf, 1))
73 		return 0;
74 
75 	if(write(w->data, new, strlen(new)) != strlen(new))
76 		return 0;
77 
78 	return 1;
79 }
80 
81 /*
82  * find the playing string, and remove it.
83  * return the string at the beginning of hte next line in buf
84  * (presumably a track number).
85  */
86 static int
unmarkplay(Window * w,char * buf,int n,ulong * q0,ulong * q1,ulong * qbegin)87 unmarkplay(Window *w, char *buf, int n, ulong *q0, ulong *q1, ulong *qbegin)
88 {
89 	char xbuf[24];
90 
91 	if(!findplay(w, PLAYSTRINGSPACE, q0, q1))
92 		return 0;
93 
94 	if(write(w->data, "", 0) < 0 || !winsetaddr(w, "+1+#0", 1))
95 		return 0;
96 
97 	if(qbegin) {
98 		seek(w->addr, 0, 0);
99 		if(read(w->addr, xbuf, 24) != 24)
100 			return 0;
101 		*qbegin = atoi(xbuf);
102 	}
103 
104 	if(buf) {
105 		if((n = read(w->data, buf, n-1)) < 0)
106 			return 0;
107 
108 		buf[n] = '\0';
109 	}
110 
111 	return 1;
112 }
113 
114 int
markplay(Window * w,ulong q0)115 markplay(Window *w, ulong q0)
116 {
117 	char buf[20];
118 
119 	if(w->data < 0)
120 		w->data = winopenfile(w, "data");
121 
122 	sprint(buf, "#%lud", q0);
123 	DPRINT(2, "addr %s\n", buf);
124 	if(!winsetaddr(w, buf, 1) || !winsetaddr(w, "-0", 1))
125 		return 0;
126 	if(write(w->data, INITSTRING, strlen(INITSTRING)) != strlen(INITSTRING))
127 		return 0;
128 	return 1;
129 }
130 
131 /* return 1 if handled, 0 otherwise */
132 int
cdcommand(Window * w,Drive * d,char * s)133 cdcommand(Window *w, Drive *d, char *s)
134 {
135 	s = skip(s, "");
136 
137 	if(iscmd(s, "Del")){
138 		if(windel(w, 0))
139 			threadexitsall(nil);
140 		return 1;
141 	}
142 	if(iscmd(s, "Stop")){
143 		unmarkplay(w, nil, 0, nil, nil, nil);
144 		stop(d);
145 		return 1;
146 	}
147 	if(iscmd(s, "Eject")){
148 		unmarkplay(w, nil, 0, nil, nil, nil);
149 		eject(d);
150 		return 1;
151 	}
152 	if(iscmd(s, "Ingest")){
153 		unmarkplay(w, nil, 0, nil, nil, nil);
154 		ingest(d);
155 		return 1;
156 	}
157 	if(iscmd(s, "Pause")){
158 		pause(d);
159 		return 1;
160 	}
161 	if(iscmd(s, "Resume")){
162 		resume(d);
163 		return 1;
164 	}
165 	return 0;
166 }
167 
168 void
drawtoc(Window * w,Drive * d,Toc * t)169 drawtoc(Window *w, Drive *d, Toc *t)
170 {
171 	int i, playing;
172 
173 	if(w->data < 0)
174 		w->data = winopenfile(w, "data");
175 	if(!winsetaddr(w, ",", 1))
176 		return;
177 
178 	fprint(w->data, "Title\n\n");
179 	playing = -1;
180 	if(d->status.state == Splaying || d->status.state == Spaused)
181 		playing = d->status.track-t->track0;
182 
183 	for(i=0; i<t->ntrack; i++)
184 		fprint(w->data, "%s%d/ Track %d\n", i==playing ? "> " : "", i+1, i+1);
185 	fprint(w->data, "");
186 }
187 
188 void
redrawtoc(Window * w,Toc * t)189 redrawtoc(Window *w, Toc *t)
190 {
191 	int i;
192 	char old[50];
193 
194 	if(w->data < 0)
195 		w->data = winopenfile(w, "data");
196 	if(t->title) {
197 		if(winsetaddr(w, "/Title", 1))
198 			write(w->data, t->title, strlen(t->title));
199 	}
200 	for(i=0; i<t->ntrack; i++) {
201 		if(t->track[i].title) {
202 			sprint(old, "/Track %d", i+1);
203 			if(winsetaddr(w, old, 1))
204 				write(w->data, t->track[i].title, strlen(t->track[i].title));
205 		}
206 	}
207 }
208 
209 void
advancetrack(Drive * d,Window * w)210 advancetrack(Drive *d, Window *w)
211 {
212 	int n;
213 	ulong q0, q1, qnext;
214 	char buf[20];
215 
216 	q0 = q1 = 0;
217 	if(!unmarkplay(w, buf, sizeof(buf), &q0, &q1, &qnext)) {
218 		DPRINT(2, "unmark: %r\n");
219 		return;
220 	}
221 
222 	DPRINT(2, "buf: %s\n", buf);
223 	if(strncmp(buf, "repeat", 6) == 0) {
224 		if(!winsetaddr(w, "#0", 1) || !findplay(w, "/^[0-9]+\\/", &qnext, nil)) {
225 			DPRINT(2, "set/find: %r\n");
226 			return;
227 		}
228 		if(w->data < 0)
229 			w->data = winopenfile(w, "data");
230 		if((n = read(w->data, buf, sizeof(buf)-1)) <= 0) {
231 			DPRINT(2, "read %d: %r\n", n);
232 			return;
233 		}
234 		buf[n] = 0;
235 		DPRINT(2, "buf: %s\n", buf);
236 	}
237 
238 	if((n = atoi(buf)) == 0)
239 		return;
240 
241 	if(!markplay(w, qnext))
242 		DPRINT(2, "err: %r");
243 
244 	playtrack(d, n-1, n-1);
245 }
246 
247 void
acmeevent(Drive * d,Window * w,Event * e)248 acmeevent(Drive *d, Window *w, Event *e)
249 {
250 	Event *ea, *e2, *eq;
251 	char *s, *t, *buf;
252 	int n, na;
253 	ulong q0, q1;
254 
255 	switch(e->c1){	/* origin of action */
256 	default:
257 	Unknown:
258 		fprint(2, "unknown message %c%c\n", e->c1, e->c2);
259 		break;
260 
261 	case 'E':	/* write to body or tag; can't affect us */
262 		break;
263 
264 	case 'F':	/* generated by our actions; ignore */
265 		break;
266 
267 	case 'K':	/* type away; we don't care */
268 		break;
269 
270 	case 'M':	/* mouse event */
271 		switch(e->c2){		/* type of action */
272 		case 'x':	/* mouse: button 2 in tag */
273 		case 'X':	/* mouse: button 2 in body */
274 			ea = nil;
275 		//	e2 = nil;
276 			s = e->b;
277 			if(e->flag & 2){	/* null string with non-null expansion */
278 				e2 = recvp(w->cevent);
279 				if(e->nb==0)
280 					s = e2->b;
281 			}
282 			if(e->flag & 8){	/* chorded argument */
283 				ea = recvp(w->cevent);	/* argument */
284 				na = ea->nb;
285 				recvp(w->cevent);		/* ignore origin */
286 			}else
287 				na = 0;
288 
289 			/* append chorded arguments */
290 			if(na){
291 				t = emalloc(strlen(s)+1+na+1);
292 				sprint(t, "%s %s", s, ea->b);
293 				s = t;
294 			}
295 			/* if it's a known command, do it */
296 			/* if it's a long message, it can't be for us anyway */
297 			DPRINT(2, "exec: %s\n", s);
298 			if(!cdcommand(w, d, s))	/* send it back */
299 				winwriteevent(w, e);
300 			if(na)
301 				free(s);
302 			break;
303 
304 		case 'l':	/* mouse: button 3 in tag */
305 		case 'L':	/* mouse: button 3 in body */
306 		//	buf = nil;
307 			eq = e;
308 			if(e->flag & 2){
309 				e2 = recvp(w->cevent);
310 				eq = e2;
311 			}
312 			s = eq->b;
313 			if(eq->q1>eq->q0 && eq->nb==0){
314 				buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
315 				winread(w, eq->q0, eq->q1, buf);
316 				s = buf;
317 			}
318 			DPRINT(2, "load %s\n", s);
319 			if((n = atoi(s)) != 0) {
320 				DPRINT(2, "mark %d\n", n);
321 				q0 = q1 = 0;
322 				unmarkplay(w, nil, 0, &q0, &q1, nil);
323 
324 				/* adjust eq->q* for deletion */
325 				if(eq->q0 > q1) {
326 					eq->q0 -= (q1-q0);
327 					eq->q1 -= (q1-q0);
328 				}
329 				if(!markplay(w, eq->q0))
330 					DPRINT(2, "err: %r\n");
331 
332 				playtrack(d, n-1, n-1);
333 			} else
334 				winwriteevent(w, e);
335 			break;
336 
337 		case 'i':	/* mouse: text inserted in tag */
338 		case 'I':	/* mouse: text inserted in body */
339 		case 'd':	/* mouse: text deleted from tag */
340 		case 'D':	/* mouse: text deleted from body */
341 			break;
342 
343 		default:
344 			goto Unknown;
345 		}
346 	}
347 }
348