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