util.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. static Point prevmouse;
  14. static Window *mousew;
  15. void
  16. cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
  17. {
  18. uchar *q;
  19. Rune *s;
  20. int j, w;
  21. /*
  22. * Always guaranteed that n bytes may be interpreted
  23. * without worrying about partial runes. This may mean
  24. * reading up to UTFmax-1 more bytes than n; the caller
  25. * knows this. If n is a firm limit, the caller should
  26. * set p[n] = 0.
  27. */
  28. q = (uchar*)p;
  29. s = r;
  30. for(j=0; j<n; j+=w){
  31. if(*q < Runeself){
  32. w = 1;
  33. *s = *q++;
  34. }else{
  35. w = chartorune(s, (char*)q);
  36. q += w;
  37. }
  38. if(*s)
  39. s++;
  40. else if(nulls)
  41. *nulls = TRUE;
  42. }
  43. *nb = (char*)q-p;
  44. *nr = s-r;
  45. }
  46. void
  47. error(char *s)
  48. {
  49. fprint(2, "acme: %s: %r\n", s);
  50. remove(acmeerrorfile);
  51. abort();
  52. }
  53. Window*
  54. errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
  55. {
  56. Window *w;
  57. Rune *r;
  58. int i, n;
  59. r = runemalloc(ndir+7);
  60. if(n = ndir) /* assign = */
  61. runemove(r, dir, ndir);
  62. runemove(r+n, L"+Errors", 7);
  63. n += 7;
  64. w = lookfile(r, n);
  65. if(w == nil){
  66. if(row.ncol == 0)
  67. if(rowadd(&row, nil, -1) == nil)
  68. error("can't create column to make error window");
  69. w = coladd(row.col[row.ncol-1], nil, nil, -1);
  70. w->filemenu = FALSE;
  71. winsetname(w, r, n);
  72. }
  73. free(r);
  74. for(i=nincl; --i>=0; ){
  75. n = runestrlen(incl[i]);
  76. r = runemalloc(n);
  77. runemove(r, incl[i], n);
  78. winaddincl(w, r, n);
  79. }
  80. return w;
  81. }
  82. /* make new window, if necessary; return with it locked */
  83. Window*
  84. errorwin(Mntdir *md, int owner)
  85. {
  86. Window *w;
  87. for(;;){
  88. if(md == nil)
  89. w = errorwin1(nil, 0, nil, 0);
  90. else
  91. w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
  92. winlock(w, owner);
  93. if(w->col != nil)
  94. break;
  95. /* window was deleted too fast */
  96. winunlock(w);
  97. }
  98. return w;
  99. }
  100. void
  101. warning(Mntdir *md, char *s, ...)
  102. {
  103. Rune *r;
  104. int nr, q0, owner;
  105. Window *w;
  106. Text *t;
  107. va_list arg;
  108. va_start(arg, s);
  109. r = runevsmprint(s, arg);
  110. va_end(arg);
  111. if(r == nil)
  112. error("runevsmprint failed");
  113. nr = runestrlen(r);
  114. if(row.ncol == 0){ /* really early error */
  115. rowinit(&row, screen->clipr);
  116. rowadd(&row, nil, -1);
  117. rowadd(&row, nil, -1);
  118. if(row.ncol == 0)
  119. error("initializing columns in warning()");
  120. }
  121. w = errorwin(md, 'E');
  122. t = &w->body;
  123. owner = w->owner;
  124. if(owner == 0)
  125. w->owner = 'E';
  126. wincommit(w, t);
  127. q0 = textbsinsert(t, t->file->nc, r, nr, TRUE, &nr);
  128. textshow(t, q0, q0+nr, 1);
  129. winsettag(t->w);
  130. textscrdraw(t);
  131. w->owner = owner;
  132. w->dirty = FALSE;
  133. winunlock(w);
  134. free(r);
  135. }
  136. int
  137. runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
  138. {
  139. if(n1 != n2)
  140. return FALSE;
  141. return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
  142. }
  143. uint
  144. min(uint a, uint b)
  145. {
  146. if(a < b)
  147. return a;
  148. return b;
  149. }
  150. uint
  151. max(uint a, uint b)
  152. {
  153. if(a > b)
  154. return a;
  155. return b;
  156. }
  157. char*
  158. runetobyte(Rune *r, int n)
  159. {
  160. char *s;
  161. if(n == 0)
  162. return nil;
  163. s = emalloc(n*UTFmax+1);
  164. setmalloctag(s, getcallerpc(&r));
  165. snprint(s, n*UTFmax+1, "%.*S", n, r);
  166. return s;
  167. }
  168. Rune*
  169. bytetorune(char *s, int *ip)
  170. {
  171. Rune *r;
  172. int nb, nr;
  173. nb = strlen(s);
  174. r = runemalloc(nb+1);
  175. cvttorunes(s, nb, r, &nb, &nr, nil);
  176. r[nr] = '\0';
  177. *ip = nr;
  178. return r;
  179. }
  180. int
  181. isalnum(Rune c)
  182. {
  183. /*
  184. * Hard to get absolutely right. Use what we know about ASCII
  185. * and assume anything above the Latin control characters is
  186. * potentially an alphanumeric.
  187. */
  188. if(c <= ' ')
  189. return FALSE;
  190. if(0x7F<=c && c<=0xA0)
  191. return FALSE;
  192. if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
  193. return FALSE;
  194. return TRUE;
  195. }
  196. int
  197. rgetc(void *v, uint n)
  198. {
  199. return ((Rune*)v)[n];
  200. }
  201. int
  202. tgetc(void *a, uint n)
  203. {
  204. Text *t;
  205. t = a;
  206. if(n >= t->file->nc)
  207. return 0;
  208. return textreadc(t, n);
  209. }
  210. Rune*
  211. skipbl(Rune *r, int n, int *np)
  212. {
  213. while(n>0 && *r==' ' || *r=='\t' || *r=='\n'){
  214. --n;
  215. r++;
  216. }
  217. *np = n;
  218. return r;
  219. }
  220. Rune*
  221. findbl(Rune *r, int n, int *np)
  222. {
  223. while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
  224. --n;
  225. r++;
  226. }
  227. *np = n;
  228. return r;
  229. }
  230. void
  231. savemouse(Window *w)
  232. {
  233. prevmouse = mouse->xy;
  234. mousew = w;
  235. }
  236. void
  237. restoremouse(Window *w)
  238. {
  239. if(mousew!=nil && mousew==w)
  240. moveto(mousectl, prevmouse);
  241. mousew = nil;
  242. }
  243. void
  244. clearmouse()
  245. {
  246. mousew = nil;
  247. }
  248. char*
  249. estrdup(char *s)
  250. {
  251. char *t;
  252. t = strdup(s);
  253. if(t == nil)
  254. error("strdup failed");
  255. setmalloctag(t, getcallerpc(&s));
  256. return t;
  257. }
  258. void*
  259. emalloc(uint n)
  260. {
  261. void *p;
  262. p = malloc(n);
  263. if(p == nil)
  264. error("malloc failed");
  265. setmalloctag(p, getcallerpc(&n));
  266. memset(p, 0, n);
  267. return p;
  268. }
  269. void*
  270. erealloc(void *p, uint n)
  271. {
  272. p = realloc(p, n);
  273. if(p == nil)
  274. error("realloc failed");
  275. setmalloctag(p, getcallerpc(&n));
  276. return p;
  277. }
  278. /*
  279. * Heuristic city.
  280. */
  281. Window*
  282. makenewwindow(Text *t)
  283. {
  284. Column *c;
  285. Window *w, *bigw, *emptyw;
  286. Text *emptyb;
  287. int i, y, el;
  288. if(activecol)
  289. c = activecol;
  290. else if(seltext && seltext->col)
  291. c = seltext->col;
  292. else if(t && t->col)
  293. c = t->col;
  294. else{
  295. if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
  296. error("can't make column");
  297. c = row.col[row.ncol-1];
  298. }
  299. activecol = c;
  300. if(t==nil || t->w==nil || c->nw==0)
  301. return coladd(c, nil, nil, -1);
  302. /* find biggest window and biggest blank spot */
  303. emptyw = c->w[0];
  304. bigw = emptyw;
  305. for(i=1; i<c->nw; i++){
  306. w = c->w[i];
  307. /* use >= to choose one near bottom of screen */
  308. if(w->body.maxlines >= bigw->body.maxlines)
  309. bigw = w;
  310. if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines)
  311. emptyw = w;
  312. }
  313. emptyb = &emptyw->body;
  314. el = emptyb->maxlines-emptyb->nlines;
  315. /* if empty space is big, use it */
  316. if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2))
  317. y = emptyb->r.min.y+emptyb->nlines*font->height;
  318. else{
  319. /* if this window is in column and isn't much smaller, split it */
  320. if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
  321. bigw = t->w;
  322. y = (bigw->r.min.y + bigw->r.max.y)/2;
  323. }
  324. w = coladd(c, nil, nil, y);
  325. if(w->body.maxlines < 2)
  326. colgrow(w->col, w, 1);
  327. return w;
  328. }