1 #include "acd.h" 2 3 static int 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* 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 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 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 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 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 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 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 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 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 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