ref: b7a4dab54ab89f9cd62f3a31166cff553450cd28
dir: /acme/bin/source/acd/acme.c/
#include "acd.h" static int iscmd(char *s, char *cmd) { int len; len = strlen(cmd); return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n'); } static char* skip(char *s, char *cmd) { s += strlen(cmd); while(*s==' ' || *s=='\t' || *s=='\n') s++; return s; } //#define PLAYSTRING "/^[0-9:]+>" //#define PLAYSTRINGSPACE "/^[0-9:]+> ?" //#define INITSTRING "0:00> " #define INITSTRING "> " #define PLAYSTRING "/^>" #define PLAYSTRINGSPACE "/^> ?" /* * find the playing string, leave in addr * if q0, q1 are non-nil, set them to the addr of the string. */ int findplay(Window *w, char *s, ulong *q0, ulong *q1) { char xbuf[25]; if(w->data < 0) w->data = winopenfile(w, "data"); if(!winsetaddr(w, "#0", 1) || !winsetaddr(w, s, 1)) return 0; seek(w->addr, 0, 0); if(read(w->addr, xbuf, 24) != 24) return 0; xbuf[24] = 0; if(q0) *q0 = atoi(xbuf); if(q1) *q1 = atoi(xbuf+12); return 1; } /* * find the playing string and replace the time */ int setplaytime(Window *w, char *new) { char buf[40]; ulong q0, q1; return 1; if(!findplay(w, PLAYSTRING, &q0, &q1)) return 0; q1--; /* > */ sprint(buf, "#%lud,#%lud", q0, q1); DPRINT(2, "setaddr %s\n", buf); if(!winsetaddr(w, buf, 1)) return 0; if(write(w->data, new, strlen(new)) != strlen(new)) return 0; return 1; } /* * find the playing string, and remove it. * return the string at the beginning of hte next line in buf * (presumably a track number). */ static int unmarkplay(Window *w, char *buf, int n, ulong *q0, ulong *q1, ulong *qbegin) { char xbuf[24]; if(!findplay(w, PLAYSTRINGSPACE, q0, q1)) return 0; if(write(w->data, "", 0) < 0 || !winsetaddr(w, "+1+#0", 1)) return 0; if(qbegin) { seek(w->addr, 0, 0); if(read(w->addr, xbuf, 24) != 24) return 0; *qbegin = atoi(xbuf); } if(buf) { if((n = read(w->data, buf, n-1)) < 0) return 0; buf[n] = '\0'; } return 1; } int markplay(Window *w, ulong q0) { char buf[20]; if(w->data < 0) w->data = winopenfile(w, "data"); sprint(buf, "#%lud", q0); DPRINT(2, "addr %s\n", buf); if(!winsetaddr(w, buf, 1) || !winsetaddr(w, "-0", 1)) return 0; if(write(w->data, INITSTRING, strlen(INITSTRING)) != strlen(INITSTRING)) return 0; return 1; } /* return 1 if handled, 0 otherwise */ int cdcommand(Window *w, Drive *d, char *s) { s = skip(s, ""); if(iscmd(s, "Del")){ if(windel(w, 0)) threadexitsall(nil); return 1; } if(iscmd(s, "Stop")){ unmarkplay(w, nil, 0, nil, nil, nil); stop(d); return 1; } if(iscmd(s, "Eject")){ unmarkplay(w, nil, 0, nil, nil, nil); eject(d); return 1; } if(iscmd(s, "Ingest")){ unmarkplay(w, nil, 0, nil, nil, nil); ingest(d); return 1; } if(iscmd(s, "Pause")){ pause(d); return 1; } if(iscmd(s, "Resume")){ resume(d); return 1; } return 0; } void drawtoc(Window *w, Drive *d, Toc *t) { int i, playing; if(w->data < 0) w->data = winopenfile(w, "data"); if(!winsetaddr(w, ",", 1)) return; fprint(w->data, "Title\n\n"); playing = -1; if(d->status.state == Splaying || d->status.state == Spaused) playing = d->status.track-t->track0; for(i=0; i<t->ntrack; i++) fprint(w->data, "%s%d/ Track %d\n", i==playing ? "> " : "", i+1, i+1); fprint(w->data, ""); } void redrawtoc(Window *w, Toc *t) { int i; char old[50]; if(w->data < 0) w->data = winopenfile(w, "data"); if(t->title) { if(winsetaddr(w, "/Title", 1)) write(w->data, t->title, strlen(t->title)); } for(i=0; i<t->ntrack; i++) { if(t->track[i].title) { sprint(old, "/Track %d", i+1); if(winsetaddr(w, old, 1)) write(w->data, t->track[i].title, strlen(t->track[i].title)); } } } void advancetrack(Drive *d, Window *w) { int n; ulong q0, q1, qnext; char buf[20]; q0 = q1 = 0; if(!unmarkplay(w, buf, sizeof(buf), &q0, &q1, &qnext)) { DPRINT(2, "unmark: %r\n"); return; } DPRINT(2, "buf: %s\n", buf); if(strncmp(buf, "repeat", 6) == 0) { if(!winsetaddr(w, "#0", 1) || !findplay(w, "/^[0-9]+\\/", &qnext, nil)) { DPRINT(2, "set/find: %r\n"); return; } if(w->data < 0) w->data = winopenfile(w, "data"); if((n = read(w->data, buf, sizeof(buf)-1)) <= 0) { DPRINT(2, "read %d: %r\n", n); return; } buf[n] = 0; DPRINT(2, "buf: %s\n", buf); } if((n = atoi(buf)) == 0) return; if(!markplay(w, qnext)) DPRINT(2, "err: %r"); playtrack(d, n-1, n-1); } void acmeevent(Drive *d, Window *w, Event *e) { Event *ea, *e2, *eq; char *s, *t, *buf; int n, na; ulong q0, q1; switch(e->c1){ /* origin of action */ default: Unknown: fprint(2, "unknown message %c%c\n", e->c1, e->c2); break; case 'E': /* write to body or tag; can't affect us */ break; case 'F': /* generated by our actions; ignore */ break; case 'K': /* type away; we don't care */ break; case 'M': /* mouse event */ switch(e->c2){ /* type of action */ case 'x': /* mouse: button 2 in tag */ case 'X': /* mouse: button 2 in body */ ea = nil; // e2 = nil; s = e->b; if(e->flag & 2){ /* null string with non-null expansion */ e2 = recvp(w->cevent); if(e->nb==0) s = e2->b; } if(e->flag & 8){ /* chorded argument */ ea = recvp(w->cevent); /* argument */ na = ea->nb; recvp(w->cevent); /* ignore origin */ }else na = 0; /* append chorded arguments */ if(na){ t = emalloc(strlen(s)+1+na+1); sprint(t, "%s %s", s, ea->b); s = t; } /* if it's a known command, do it */ /* if it's a long message, it can't be for us anyway */ DPRINT(2, "exec: %s\n", s); if(!cdcommand(w, d, s)) /* send it back */ winwriteevent(w, e); if(na) free(s); break; case 'l': /* mouse: button 3 in tag */ case 'L': /* mouse: button 3 in body */ // buf = nil; eq = e; if(e->flag & 2){ e2 = recvp(w->cevent); eq = e2; } s = eq->b; if(eq->q1>eq->q0 && eq->nb==0){ buf = emalloc((eq->q1-eq->q0)*UTFmax+1); winread(w, eq->q0, eq->q1, buf); s = buf; } DPRINT(2, "load %s\n", s); if((n = atoi(s)) != 0) { DPRINT(2, "mark %d\n", n); q0 = q1 = 0; unmarkplay(w, nil, 0, &q0, &q1, nil); /* adjust eq->q* for deletion */ if(eq->q0 > q1) { eq->q0 -= (q1-q0); eq->q1 -= (q1-q0); } if(!markplay(w, eq->q0)) DPRINT(2, "err: %r\n"); playtrack(d, n-1, n-1); } else winwriteevent(w, e); break; case 'i': /* mouse: text inserted in tag */ case 'I': /* mouse: text inserted in body */ case 'd': /* mouse: text deleted from tag */ case 'D': /* mouse: text deleted from body */ break; default: goto Unknown; } } }