acme.c 6.9 KB

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