util.b 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. implement Utils;
  2. include "common.m";
  3. include "sh.m";
  4. include "env.m";
  5. sys : Sys;
  6. draw : Draw;
  7. gui : Gui;
  8. acme : Acme;
  9. dat : Dat;
  10. graph : Graph;
  11. textm : Textm;
  12. windowm : Windowm;
  13. columnm : Columnm;
  14. rowm : Rowm;
  15. scrl : Scroll;
  16. look : Look;
  17. RELEASECOPY : import acme;
  18. Point, Rect : import draw;
  19. Astring, TRUE, FALSE, Mntdir, Lock : import dat;
  20. mouse, activecol, seltext, row : import dat;
  21. cursorset : import graph;
  22. mainwin : import gui;
  23. Text : import textm;
  24. Window : import windowm;
  25. Column : import columnm;
  26. Row : import rowm;
  27. init(mods : ref Dat->Mods)
  28. {
  29. sys = mods.sys;
  30. draw = mods.draw;
  31. gui = mods.gui;
  32. acme = mods.acme;
  33. dat = mods.dat;
  34. graph = mods.graph;
  35. textm = mods.textm;
  36. windowm = mods.windowm;
  37. columnm = mods.columnm;
  38. rowm = mods.rowm;
  39. scrl = mods.scroll;
  40. look = mods.look;
  41. stderr = sys->fildes(2);
  42. }
  43. min(x : int, y : int) : int
  44. {
  45. if (x < y)
  46. return x;
  47. return y;
  48. }
  49. max(x : int, y : int) : int
  50. {
  51. if (x > y)
  52. return x;
  53. return y;
  54. }
  55. abs(x : int) : int
  56. {
  57. if (x < 0)
  58. return -x;
  59. return x;
  60. }
  61. isalnum(c : int) : int
  62. {
  63. #
  64. # Hard to get absolutely right. Use what we know about ASCII
  65. # and assume anything above the Latin control characters is
  66. # potentially an alphanumeric.
  67. #
  68. if(c <= ' ')
  69. return FALSE;
  70. if(16r7F<=c && c<=16rA0)
  71. return FALSE;
  72. if(strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c) >= 0)
  73. return FALSE;
  74. return TRUE;
  75. # return ('a' <= c && c <= 'z') ||
  76. # ('A' <= c && c <= 'Z') ||
  77. # ('0' <= c && c <= '9');
  78. }
  79. strchr(s : string, c : int) : int
  80. {
  81. for (i := 0; i < len s; i++)
  82. if (s[i] == c)
  83. return i;
  84. return -1;
  85. }
  86. strrchr(s : string, c : int) : int
  87. {
  88. for (i := len s - 1; i >= 0; i--)
  89. if (s[i] == c)
  90. return i;
  91. return -1;
  92. }
  93. strncmp(s, t : string, n : int) : int
  94. {
  95. if (len s > n)
  96. s = s[0:n];
  97. if (len t > n)
  98. t = t[0:n];
  99. if (s < t)
  100. return -1;
  101. if (s > t)
  102. return 1;
  103. return 0;
  104. }
  105. env : Env;
  106. getenv(s : string) : string
  107. {
  108. if (env == nil)
  109. env = load Env Env->PATH;
  110. e := env->getenv(s);
  111. if(e != nil && e[len e - 1] == '\n') # shell bug
  112. return e[0: len e -1];
  113. return e;
  114. }
  115. setenv(s, t : string)
  116. {
  117. if (env == nil)
  118. env = load Env Env->PATH;
  119. env->setenv(s, t);
  120. }
  121. stob(s : string, n : int) : array of byte
  122. {
  123. b := array[2*n] of byte;
  124. for (i := 0; i < n; i++) {
  125. b[2*i] = byte (s[i]&16rff);
  126. b[2*i+1] = byte ((s[i]>>8)&16rff);
  127. }
  128. return b;
  129. }
  130. btos(b : array of byte, s : ref Astring)
  131. {
  132. n := (len b)/2;
  133. for (i := 0; i < n; i++)
  134. s.s[i] = int b[2*i] | ((int b[2*i+1])<<8);
  135. }
  136. reverse(ol : list of string) : list of string
  137. {
  138. nl : list of string;
  139. nl = nil;
  140. while (ol != nil) {
  141. nl = hd ol :: nl;
  142. ol = tl ol;
  143. }
  144. return nl;
  145. }
  146. nextarg(p : ref Arg) : int
  147. {
  148. bp : string;
  149. if(p.av != nil){
  150. bp = hd p.av;
  151. if(bp != nil && bp[0] == '-'){
  152. p.p = bp[1:];
  153. p.av = tl p.av;
  154. return 1;
  155. }
  156. }
  157. p.p = nil;
  158. return 0;
  159. }
  160. arginit(av : list of string) : ref Arg
  161. {
  162. p : ref Arg;
  163. p = ref Arg;
  164. p.arg0 = hd av;
  165. p.av = tl av;
  166. nextarg(p);
  167. return p;
  168. }
  169. argopt(p : ref Arg) : int
  170. {
  171. r : int;
  172. if(p.p == nil && nextarg(p) == 0)
  173. return 0;
  174. r = p.p[0];
  175. p.p = p.p[1:];
  176. return r;
  177. }
  178. argf(p : ref Arg) : string
  179. {
  180. bp : string;
  181. if(p.p != nil){
  182. bp = p.p;
  183. p.p = nil;
  184. } else if(p.av != nil){
  185. bp = hd p.av;
  186. p.av = tl p.av;
  187. } else
  188. bp = nil;
  189. return bp;
  190. }
  191. exec(cmd : string, argl : list of string)
  192. {
  193. file := cmd;
  194. if(len file<4 || file[len file-4:]!=".dis")
  195. file += ".dis";
  196. c := load Command file;
  197. if(c == nil) {
  198. err := sys->sprint("%r");
  199. if(file[0]!='/' && file[0:2]!="./"){
  200. c = load Command "/dis/"+file;
  201. if(c == nil)
  202. err = sys->sprint("%r");
  203. }
  204. if(c == nil){
  205. # debug(sys->sprint("file %s not found\n", file));
  206. sys->fprint(stderr, "%s: %s\n", cmd, err);
  207. return;
  208. }
  209. }
  210. c->init(acme->acmectxt, argl);
  211. }
  212. getuser() : string
  213. {
  214. fd := sys->open("/dev/user", sys->OREAD);
  215. if(fd == nil)
  216. return "";
  217. buf := array[128] of byte;
  218. n := sys->read(fd, buf, len buf);
  219. if(n < 0)
  220. return "";
  221. return string buf[0:n];
  222. }
  223. gethome(usr : string) : string
  224. {
  225. if (usr == nil)
  226. usr = "tmp";
  227. return "/usr/" + usr;
  228. }
  229. postnote(t : int, this : int, pid : int, note : string) : int
  230. {
  231. if (pid == this || pid == 0)
  232. return 0;
  233. # fd := sys->open("/prog/" + string pid + "/ctl", sys->OWRITE);
  234. fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
  235. if (fd == nil)
  236. return -1;
  237. if (t == PNGROUP)
  238. note += "grp";
  239. sys->fprint(fd, "%s", note);
  240. fd = nil;
  241. return 0;
  242. }
  243. error(s : string)
  244. {
  245. sys->fprint(stderr, "acme: %s: %r\n", s);
  246. debug(sys->sprint("error %s : %r\n", s));
  247. # s[-1] = 0; # create broken process for debugging
  248. acme->acmeexit("error");
  249. }
  250. dlock : ref Lock;
  251. dfd : ref Sys->FD;
  252. debuginit()
  253. {
  254. if (RELEASECOPY)
  255. return;
  256. dfd = sys->create("./debug", Sys->OWRITE, 8r600);
  257. # fd = nil;
  258. dlock = Lock.init();
  259. }
  260. debugpr(s : string)
  261. {
  262. if (RELEASECOPY)
  263. return;
  264. # fd := sys->open("./debug", Sys->OWRITE);
  265. # sys->seek(fd, big 0, Sys->SEEKEND);
  266. sys->fprint(dfd, "%s", s);
  267. # fd = nil;
  268. }
  269. debug(s : string)
  270. {
  271. if (RELEASECOPY)
  272. return;
  273. if (dfd == nil)
  274. return;
  275. dlock.lock();
  276. debugpr(s);
  277. dlock.unlock();
  278. }
  279. memfd : ref Sys->FD;
  280. memb : array of byte;
  281. memdebug(s : string)
  282. {
  283. if (RELEASECOPY)
  284. return;
  285. dlock.lock();
  286. if (memfd == nil) {
  287. sys->bind("#c", "/usr/jrf/mnt", Sys->MBEFORE);
  288. memfd = sys->open("/usr/jrf/mnt/memory", Sys->OREAD);
  289. memb = array[1024] of byte;
  290. }
  291. sys->seek(memfd, big 0, 0);
  292. n := sys->read(memfd, memb, len memb);
  293. if (n <= 0) {
  294. dlock.unlock();
  295. debug(sys->sprint("bad read %r\n"));
  296. return;
  297. }
  298. s = s + " : " + string memb[0:n] + "\n";
  299. dlock.unlock();
  300. debug(s);
  301. s = nil;
  302. }
  303. rgetc(s : string, n : int) : int
  304. {
  305. if (n < 0 || n >= len s)
  306. return 0;
  307. return s[n];
  308. }
  309. tgetc(t : ref Text, n : int) : int
  310. {
  311. if(n >= t.file.buf.nc)
  312. return 0;
  313. return t.readc(n);
  314. }
  315. skipbl(r : string, n : int) : (string, int)
  316. {
  317. i : int = 0;
  318. while(n>0 && (r[i]==' ' || r[i]=='\t' || r[i]=='\n')){
  319. --n;
  320. i++;
  321. }
  322. return (r[i:], n);
  323. }
  324. findbl(r : string, n : int) : (string, int)
  325. {
  326. i : int = 0;
  327. while(n>0 && r[i]!=' ' && r[i]!='\t' && r[i]!='\n'){
  328. --n;
  329. i++;
  330. }
  331. return (r[i:], n);
  332. }
  333. prevmouse : Point;
  334. mousew : ref Window;
  335. savemouse(w : ref Window)
  336. {
  337. prevmouse = mouse.xy;
  338. mousew = w;
  339. }
  340. restoremouse(w : ref Window)
  341. {
  342. if(mousew!=nil && mousew==w)
  343. cursorset(prevmouse);
  344. mousew = nil;
  345. }
  346. clearmouse()
  347. {
  348. mousew = nil;
  349. }
  350. #
  351. # Heuristic city.
  352. #
  353. newwindow(t : ref Text) : ref Window
  354. {
  355. c : ref Column;
  356. w, bigw, emptyw : ref Window;
  357. emptyb : ref Text;
  358. i, y, el : int;
  359. if(activecol != nil)
  360. c = activecol;
  361. else if(seltext != nil && seltext.col != nil)
  362. c = seltext.col;
  363. else if(t != nil && t.col != nil)
  364. c = t.col;
  365. else{
  366. if(row.ncol==0 && row.add(nil, -1)==nil)
  367. error("can't make column");
  368. c = row.col[row.ncol-1];
  369. }
  370. activecol = c;
  371. if(t==nil || t.w==nil || c.nw==0)
  372. return c.add(nil, nil, -1);
  373. # find biggest window and biggest blank spot
  374. emptyw = c.w[0];
  375. bigw = emptyw;
  376. for(i=1; i<c.nw; i++){
  377. w = c.w[i];
  378. # use >= to choose one near bottom of screen
  379. if(w.body.frame.maxlines >= bigw.body.frame.maxlines)
  380. bigw = w;
  381. if(w.body.frame.maxlines-w.body.frame.nlines >= emptyw.body.frame.maxlines-emptyw.body.frame.nlines)
  382. emptyw = w;
  383. }
  384. emptyb = emptyw.body;
  385. el = emptyb.frame.maxlines-emptyb.frame.nlines;
  386. # if empty space is big, use it
  387. if(el>15 || (el>3 && el>(bigw.body.frame.maxlines-1)/2))
  388. y = emptyb.frame.r.min.y+emptyb.frame.nlines*(graph->font).height;
  389. else{
  390. # if this window is in column and isn't much smaller, split it
  391. if(t.col==c && t.w.r.dy()>2*bigw.r.dy()/3)
  392. bigw = t.w;
  393. y = (bigw.r.min.y + bigw.r.max.y)/2;
  394. }
  395. w = c.add(nil, nil, y);
  396. if(w.body.frame.maxlines < 2)
  397. w.col.grow(w, 1, 1);
  398. return w;
  399. }
  400. stralloc(n : int) : ref Astring
  401. {
  402. r := ref Astring;
  403. ab := array[n] of { * => byte 'z' };
  404. r.s = string ab;
  405. if (len r.s != n)
  406. error("bad stralloc");
  407. ab = nil;
  408. return r;
  409. }
  410. strfree(s : ref Astring)
  411. {
  412. s.s = nil;
  413. s = nil;
  414. }
  415. access(s : string) : int
  416. {
  417. fd := sys->open(s, 0);
  418. if (fd == nil)
  419. return -1;
  420. fd = nil;
  421. return 0;
  422. }
  423. errorwin(dir : string, ndir : int, incl : array of string, nincl : int) : ref Window
  424. {
  425. w : ref Window;
  426. r : string;
  427. i, n : int;
  428. n = ndir;
  429. r = dir + "+Errors";
  430. n += 7;
  431. w = look->lookfile(r, n);
  432. if(w == nil){
  433. w = row.col[row.ncol-1].add(nil, nil, -1);
  434. w.filemenu = FALSE;
  435. w.setname(r, n);
  436. }
  437. r = nil;
  438. for(i=nincl; --i>=0; )
  439. w.addincl(incl[i], n);
  440. return w;
  441. }
  442. warning(md : ref Mntdir, s : string)
  443. {
  444. n, q0, owner : int;
  445. w : ref Window;
  446. t : ref Text;
  447. debug(sys->sprint("warning %s\n", s));
  448. if (row == nil) {
  449. sys->fprint(sys->fildes(2), "warning: %s\n", s);
  450. debug(s);
  451. debug("\n");
  452. return;
  453. }
  454. if(row.ncol == 0){ # really early error
  455. row.init(mainwin.clipr);
  456. row.add(nil, -1);
  457. row.add(nil, -1);
  458. if(row.ncol == 0)
  459. error("initializing columns in warning()");
  460. }
  461. if(md != nil){
  462. for(;;){
  463. w = errorwin(md.dir, md.ndir, md.incl, md.nincl);
  464. w.lock('E');
  465. if (w.col != nil)
  466. break;
  467. # window was deleted too fast
  468. w.unlock();
  469. }
  470. }else
  471. w = errorwin(nil, 0, nil, 0);
  472. t = w.body;
  473. owner = w.owner;
  474. if(owner == 0)
  475. w.owner = 'E';
  476. w.commit(t);
  477. (q0, n) = t.bsinsert(t.file.buf.nc, s, len s, TRUE);
  478. t.show(q0, q0+n, TRUE);
  479. t.w.settag();
  480. scrl->scrdraw(t);
  481. w.owner = owner;
  482. w.dirty = FALSE;
  483. if(md != nil)
  484. w.unlock();
  485. }
  486. getexc(): string
  487. {
  488. f := "/prog/"+string sys->pctl(0, nil)+"/exception";
  489. if((fd := sys->open(f, Sys->OREAD)) == nil)
  490. return nil;
  491. b := array[8192] of byte;
  492. if((n := sys->read(fd, b, len b)) < 0)
  493. return nil;
  494. return string b[0: n];
  495. }
  496. # returns pc, module, exception
  497. readexc(): (int, string, string)
  498. {
  499. s := getexc();
  500. if(s == nil)
  501. return (0, nil, nil);
  502. (m, l) := sys->tokenize(s, " ");
  503. if(m < 3)
  504. return (0, nil, nil);
  505. pc := int hd l; l = tl l;
  506. mod := hd l; l = tl l;
  507. exc := hd l; l = tl l;
  508. for( ; l != nil; l = tl l)
  509. exc += " " + hd l;
  510. return (pc, mod, exc);
  511. }