acme.c 6.5 KB

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