a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
f9322c1999-03-13Marcus Comstedt  #if constant(thread_create) #define LOCK object m_key = mutex->lock() #define UNLOCK destruct(m_key)
beb21d2008-06-28Martin Nilsson #define MUTEX protected private object(Thread.Mutex) mutex = Thread.Mutex();
f9322c1999-03-13Marcus Comstedt #else #define LOCK #define UNLOCK #define MUTEX #endif MUTEX
9eaf1d2008-06-28Martin Nilsson protected private array ctrlcharsfrom =
716c272006-01-07Martin Nilsson  map(indices(allocate(32)), lambda(int z) { return sprintf("^%c",z+64); })+ map(indices(allocate(32)), lambda(int z) { return sprintf("^%c",z+96); });
9eaf1d2008-06-28Martin Nilsson protected private array ctrlcharsto =
716c272006-01-07Martin Nilsson  map(indices(allocate(32)), lambda(int z) { return sprintf("%c",z); })+ map(indices(allocate(32)), lambda(int z) { return sprintf("%c",z); });
f9322c1999-03-13Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson protected private class TermMachine {
f9322c1999-03-13Marcus Comstedt  mapping(string:string|int) map = ([]); int tgetflag(string id) { return map[id]==1; } int tgetnum(string id) {
c83fb62000-03-30Henrik Grubbström (Grubba)  return intp(map[id]) && [int]map[id];
f9322c1999-03-13Marcus Comstedt  } string tgetstr(string id) {
c83fb62000-03-30Henrik Grubbström (Grubba)  return stringp(map[id]) && [string]map[id];
f9322c1999-03-13Marcus Comstedt  } string tparam(string f, mixed ... args) {
c83fb62000-03-30Henrik Grubbström (Grubba)  array(string) fmt=f/"%";
f9322c1999-03-13Marcus Comstedt  string res=fmt[0]; string tmp; int z; mapping var=([]); array args0=args;
c83fb62000-03-30Henrik Grubbström (Grubba) #define POP (z=[int]args[0],args=args[1..],z)
f9322c1999-03-13Marcus Comstedt #define PUSH(x) (args=({x})+args) while ( (fmt=fmt[1..])!=({}) ) if (fmt[0]=="") res+="%"; else { switch (fmt[0][0]) { case 'd': res+=sprintf("%d%s",POP,fmt[0][1..]); break; case 'x': res+=sprintf("%x%s",POP,fmt[0][1..]); break; case '0': case '2': case '3': sscanf(fmt[0],"%[0-9]%s",tmp,fmt[0]); res+=sprintf("%"+tmp+fmt[0][..0]+"%s",POP,fmt[0][1..]); break; case 'c': res+=sprintf("%c%s",POP,fmt[0][1..]); break;
c81a802007-04-06Henrik Grubbström (Grubba)  case 's': res+=sprintf("%s%s",[string](mixed)POP,fmt[0][1..]); break;
f9322c1999-03-13Marcus Comstedt  case '\'': sscanf(fmt[0],"'%s'%s",tmp,fmt[0]); if (tmp=="") tmp="\0"; if (tmp[0]=='\\') tmp=sprintf("%c",(int)("0"+tmp[1..])); PUSH(tmp[0]); res+=fmt[0]; break; case '{': sscanf(fmt[0],"{%d}%s",z,fmt[0]); res+=fmt[0]; PUSH(z); break; case 'p': PUSH(args0[fmt[0][1]-'1']); res+=fmt[0][2..]; break; case 'P': var[fmt[0][1]]=POP; res+=fmt[0][2..]; break; case 'g': PUSH(var[fmt[0][1]]); res+=fmt[0][2..]; break; case 'i': args[0]+=1; args[1]+=1; break; case '+': PUSH(POP+POP); res+=fmt[0][1..]; break; case '-': PUSH(POP-POP); res+=fmt[0][1..]; break; case '*': PUSH(POP*POP); res+=fmt[0][1..]; break; case '/': PUSH(POP/POP); res+=fmt[0][1..]; break; case 'm': PUSH(POP%POP); res+=fmt[0][1..]; break; case '&': PUSH(POP&POP); res+=fmt[0][1..]; break; case '|': PUSH(POP|POP); res+=fmt[0][1..]; break; case '^': PUSH(POP^POP); res+=fmt[0][1..]; break; case '=': PUSH(POP==POP); res+=fmt[0][1..]; break; case '>': PUSH(POP>POP); res+=fmt[0][1..]; break; case '<': PUSH(POP<POP); res+=fmt[0][1..]; break; case 'A': PUSH(POP && POP); res+=fmt[0][1..]; break; case 'O': PUSH(POP || POP); res+=fmt[0][1..]; break; case '!': PUSH(!POP); res+=fmt[0][1..]; break; case '~': PUSH(~POP); res+=fmt[0][1..]; break; case '?': error("Sorry, Terminal can't handle if-else's\n"); default: error("Unknown opcode: %%%s\n",fmt[0][..0]); } } return res; } string tgoto(string cap, int col, int row) { return tparam(cap, col, row); } string tputs(string s) { return s; } string put(string cap, mixed ... args) { string str = tgetstr(cap); string tstr = str && tparam(str, @args); return tstr && tputs(tstr); } }
6c00e02001-10-23Martin Nilsson //! Termcap terminal description object.
f9322c1999-03-13Marcus Comstedt class Termcap { inherit TermMachine;
6c00e02001-10-23Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  array(string) aliases;
6c00e02001-10-23Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected Termcap parent;
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson  //! Put termcap string
f9322c1999-03-13Marcus Comstedt  string tputs(string s) { // Delay stuff completely ignored... sscanf(s, "%*d%s", s); return s; }
9eaf1d2008-06-28Martin Nilsson  private protected multiset(string) load_cap(string en)
f9322c1999-03-13Marcus Comstedt  { string br=":"; int i=search(en,":"); int j=search(en,","); multiset(string) clears = (<>); if (i==-1) { i=j; br=","; } else if (j!=-1) { i=min(i,j); if (i==j) br=","; } if (i<1) error("Termcap: Unparsable entry\n"); aliases=en[..i-1]/"|"; en=en[i..]; while (en!="") { string name; string data;
916bab1999-11-17Fredrik Hübinette (Hubbe)  if(sscanf(en,"%*[ \t]%[a-zA-Z_0-9&]%s"+br+"%s",name,data,en) < 4) { sscanf(en,"%*[ \t]%[a-zA-Z_0-9&]%s",name,data); en=""; }
f9322c1999-03-13Marcus Comstedt  if (data=="") // boolean { if (name!="") map[name]=1; } else if (data[0]=='@') // boolean off { clears[name]=1; } else if (data[0]=='#') // number { int z; sscanf(data,"#%d",z); map[name]=z; } else if (data[0]=='=') // string { data=data[1..];
f7ba731999-09-07Marcus Comstedt  while (sizeof(data) && data[-1]=='\\')
f9322c1999-03-13Marcus Comstedt  { string add; if (sscanf(en,"%s"+br+"%s",add,en)<2) break; data+="\\"+add; } data=replace(data,"\\^","\\*");
7b69642003-08-07Martin Nilsson  if (has_value(data, "^"))
f9322c1999-03-13Marcus Comstedt  data=replace(data,ctrlcharsfrom,ctrlcharsto); data = replace(data, ({"\\E","\\e","\\n","\\r","\\t","\\b","\\f", "\\*","\\\\","\\,","\\:","#", "\\0","\\1","\\2","\\3","\\4","\\5","\\6","\\7"}), ({"\033","\033","\n","\r","\t","\b","\f", "^","\\",",",":","#!", "#0","#1","#2","#3","#4","#5","#6","#7"})); array(string) parts = data/"#"; data = parts[0]; foreach (parts[1..], string p) if (sizeof(p) && p[0]=='!') data += "#"+p[1..]; else { int n; string x; if(2==sscanf(p[..2], "%o%s", n, x)) data += sprintf("%c%s%s", n, x, p[3..]); else data += p; } map[name]=data; }
334e872003-03-12Marcus Agehall  else // weird
f9322c1999-03-13Marcus Comstedt  { // ignore } } return clears; }
6c00e02001-10-23Martin Nilsson  //!
3d0c502003-06-27Martin Nilsson  void create(string cap, TermcapDB|void tcdb, int|void maxrecurse)
f9322c1999-03-13Marcus Comstedt  { int i=0; while((i=search(cap, "\\\n", i))>=0) { string capr; if(2!=sscanf(cap[i..], "\\\n%*[ \t\r]%s", capr)) break; cap = cap[..i-1]+capr; } multiset(string) clears = load_cap(cap); if(map->tc) { if(maxrecurse==1) error("Termcap: maximum inheritance depth exceeded (loop?)\n"); parent = (tcdb||defaultTermcapDB())-> load(map->tc, maxrecurse? (maxrecurse-1):25); if(!parent) error("Termcap: can't find parent terminal \"%s\"\n", map->tc); map = parent->map | map; } map |= mkmapping(indices(clears), allocate(sizeof(clears))); } }
6c00e02001-10-23Martin Nilsson //! Terminfo terminal description object
f9322c1999-03-13Marcus Comstedt class Terminfo { inherit TermMachine;
6c00e02001-10-23Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  array(string) aliases;
9eaf1d2008-06-28Martin Nilsson  protected private constant boolnames =
f9322c1999-03-13Marcus Comstedt  ({ "bw","am","xb","xs","xn","eo","gn","hc","km","hs","in","da","db","mi", "ms","os","es","xt","hz","ul","xo","nx","5i","HC","NR","NP","ND","cc", "ut","hl","YA","YB","YC","YD","YE","YF","YG" });
9eaf1d2008-06-28Martin Nilsson  protected private constant numnames =
f9322c1999-03-13Marcus Comstedt  ({ "co","it","li","lm","sg","pb","vt","ws","Nl","lh","lw","ma","MW","Co", "pa","NC","Ya","Yb","Yc","Yd","Ye","Yf","Yg","Yh","Yi","Yj","Yk","Yl", "Ym","Yn","BT","Yo","Yp" });
9eaf1d2008-06-28Martin Nilsson  protected private constant strnames =
f9322c1999-03-13Marcus Comstedt  ({ "bt","bl","cr","cs","ct","cl","ce","cd","ch","CC","cm","do","ho","vi", "le","CM","ve","nd","ll","up","vs","dc","dl","ds","hd","as","mb","md", "ti","dm","mh","im","mk","mp","mr","so","us","ec","ae","me","te","ed", "ei","se","ue","vb","ff","fs","i1","is","i3","if","ic","al","ip","kb", "ka","kC","kt","kD","kL","kd","kM","kE","kS","k0","k1","k;","k2","k3", "k4","k5","k6","k7","k8","k9","kh","kI","kA","kl","kH","kN","kP","kr", "kF","kR","kT","ku","ke","ks","l0","l1","la","l2","l3","l4","l5","l6", "l7","l8","l9","mo","mm","nw","pc","DC","DL","DO","IC","SF","AL","LE", "RI","SR","UP","pk","pl","px","ps","pf","po","rp","r1","r2","r3","rf", "rc","cv","sc","sf","sr","sa","st","wi","ta","ts","uc","hu","iP","K1", "K3","K2","K4","K5","pO","rP","ac","pn","kB","SX","RX","SA","RA","XN", "XF","eA","LO","LF","@1","@2","@3","@4","@5","@6","@7","@8","@9","@0", "%1","%2","%3","%4","%5","%6","%7","%8","%9","%0","&1","&2","&3","&4", "&5","&6","&7","&8","&9","&0","*1","*2","*3","*4","*5","*6","*7","*8", "*9","*0","#1","#2","#3","#4","%a","%b","%c","%d","%e","%f","%g","%h", "%i","%j","!1","!2","!3","RF","F1","F2","F3","F4","F5","F6","F7","F8", "F9","FA","FB","FC","FD","FE","FF","FG","FH","FI","FJ","FK","FL","FM", "FN","FO","FP","FQ","FR","FS","FT","FU","FV","FW","FX","FY","FZ","Fa", "Fb","Fc","Fd","Fe","Ff","Fg","Fh","Fi","Fj","Fk","Fl","Fm","Fn","Fo", "Fp","Fq","Fr","cb","MC","ML","MR","Lf","SC","DK","RC","CW","WG","HU", "DI","QD","TO","PU","fh","PA","WA","u0","u1","u2","u3","u4","u5","u6", "u7","u8","u9","op","oc","Ic","Ip","sp","Sf","Sb","ZA","ZB","ZC","ZD", "ZE","ZF","ZG","ZH","ZI","ZJ","ZK","ZL","ZM","ZN","ZO","ZP","ZQ","ZR", "ZS","ZT","ZU","ZV","ZW","ZX","ZY","ZZ","Za","Zb","Zc","Zd","Ze","Zf", "Zg","Zh","Zi","Zj","Zk","Zl","Zm","Zn","Zo","Zp","Zq","Zr","Zs","Zt", "Zu","Zv","Zw","Zx","Zy","Km","Mi","RQ","Gm","AF","AB","xl","dv","ci", "s0","s1","s2","s3","ML","MT","Xy","Zz","Yv","Yw","Yx","Yy","Yz","YZ", "S1","S2","S3","S4","S5","S6","S7","S8","Xh","Xl","Xo","Xr","Xt","Xv", "sA","sL" });
6c00e02001-10-23Martin Nilsson  //! @fixme //! Document this function
f9322c1999-03-13Marcus Comstedt  string tputs(string s) { // Delay stuff completely ignored... string pre, post; while (3==sscanf(s, "%s$<%*[0-9.]>%s", pre, post)) s = pre+post; return s; }
9eaf1d2008-06-28Martin Nilsson  protected private string swab(string s)
f9322c1999-03-13Marcus Comstedt  {
716c272006-01-07Martin Nilsson  return predef::map(s/2, reverse)*"";
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected private int load_cap(.File f, int|void bug_compat)
f9322c1999-03-13Marcus Comstedt  { int magic, sname, nbool, nnum, nstr, sstr; if (6!=sscanf(swab(f->read(12)), "%2c%2c%2c%2c%2c%2c", magic, sname, nbool, nnum, nstr, sstr) || magic != 0432) return 0; aliases = (f->read(sname)-"\0")/"|"; {
401ded1999-03-18Marcus Comstedt  int blen = nbool;
b7dec12008-11-03Stefan Wallström  if(((nbool+sname)&1) && !bug_compat)
401ded1999-03-18Marcus Comstedt  blen++; array(int) bools = values(f->read(blen)[..nbool-1]);
f9322c1999-03-13Marcus Comstedt  if (sizeof(bools)>sizeof(boolnames)) bools = bools[..sizeof(boolnames)-1]; map = mkmapping(boolnames[..sizeof(bools)-1], bools); } {
c83fb62000-03-30Henrik Grubbström (Grubba)  array(int) nums = [array(int)] array_sscanf(swab(f->read(nnum*2)), "%2c"*nnum);
f9322c1999-03-13Marcus Comstedt  if (sizeof(nums)>sizeof(numnames)) nums = nums[..sizeof(numnames)-1]; mapping(string:int) tmp = mkmapping(numnames[..sizeof(nums)-1], nums); foreach (numnames[..sizeof(nums)-1], string name) if (tmp[name]>=0xfffe) m_delete(tmp, name); map += tmp; } { string stroffs = swab(f->read(nstr*2)); string strbuf = f->read(sstr);
ead9722003-01-20Martin Nilsson  if(sizeof(strbuf)==sstr-1 && !bug_compat && (nbool&1)) {
401ded1999-03-18Marcus Comstedt  // Ugh. Someone didn't pad their bool array properly (one suspects). f->seek(0); return load_cap(f, 1); }
ead9722003-01-20Martin Nilsson  if(sizeof(strbuf)!=sstr)
f9322c1999-03-13Marcus Comstedt  return 0;
716c272006-01-07Martin Nilsson  array(string) strarr = predef::map(array_sscanf(stroffs, "%2c"*nstr), lambda(int offs, string buf) { return offs<0xfffe &&
437d212006-01-07Martin Nilsson  offs<sizeof(buf) &&
716c272006-01-07Martin Nilsson  buf[offs.. search(buf, "\0", offs)-1]; }, strbuf+"\0");
f9322c1999-03-13Marcus Comstedt  if (sizeof(strarr)>sizeof(strnames)) strarr = strarr[..sizeof(strnames)-1]; mapping(string:string) tmp = mkmapping(strnames[..sizeof(strarr)-1], strarr); foreach (strnames[..sizeof(strarr)-1], string name) if (!tmp[name]) m_delete(tmp, name); map += tmp; } return 1; }
6c00e02001-10-23Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void create(string filename) {
3d0c502003-06-27Martin Nilsson  .File f = .File();
f9322c1999-03-13Marcus Comstedt  if (!f->open(filename, "r")) error("Terminfo: unable to open terminfo file \"%s\"\n", filename); int r = load_cap(f); f->close(); if (!r) error("Terminfo: unparsable terminfo file \"%s\"\n", filename); } }
fbb2252010-06-05Henrik Grubbström (Grubba) //! Termcap database
f9322c1999-03-13Marcus Comstedt class TermcapDB { MUTEX
9eaf1d2008-06-28Martin Nilsson  protected private inherit .File;
f9322c1999-03-13Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson  protected private string buf=""; protected private mapping(string:int|Termcap) cache=([]); protected private int complete_index=0;
f9322c1999-03-13Marcus Comstedt  void create(string|void filename) { if (!filename) {
c83fb62000-03-30Henrik Grubbström (Grubba)  string tce = [string]getenv("TERMCAP");
ead9722003-01-20Martin Nilsson  if (tce && sizeof(tce) && tce[0]=='/')
f9322c1999-03-13Marcus Comstedt  filename = tce;
18730e2005-01-07Henrik Grubbström (Grubba)  else if ((getenv("OSTYPE") == "msys") && (filename = getenv("SHELL"))) { // MinGW // Usually something like "C:/msys/1.0/bin/sh" // Termcap is in "C:/msys/1.0/etc/termcap" filename = combine_path(filename, "../../etc/termcap"); }
749cbb2007-04-30Henrik Grubbström (Grubba)  else { filename = "/etc/termcap"; // Default. foreach(({ "/etc/termcap", "/usr/share/termcap", "/usr/share/misc/termcap", }), string fname) { .Stat s = file_stat(fname);
99dc662007-05-01Henrik Grubbström (Grubba)  if (s && s->type == "reg") {
749cbb2007-04-30Henrik Grubbström (Grubba)  filename = fname; break; } } }
f9322c1999-03-13Marcus Comstedt  }
18730e2005-01-07Henrik Grubbström (Grubba)  if (!::open(filename, "r")) {
f9322c1999-03-13Marcus Comstedt  error("failed to open termcap file %O\n", filename);
18730e2005-01-07Henrik Grubbström (Grubba)  }
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected private void rewind(int|void pos)
f9322c1999-03-13Marcus Comstedt  { ::seek(pos); buf=""; }
9eaf1d2008-06-28Martin Nilsson  protected private int more_data()
f9322c1999-03-13Marcus Comstedt  { string q; q=::read(8192); if (q=="" || !q) return 0; buf+=q; return 1; }
9eaf1d2008-06-28Martin Nilsson  protected private array(string) get_names(string cap)
f9322c1999-03-13Marcus Comstedt  { sscanf(cap, "%s:", cap); sscanf(cap, "%s,", cap); return cap/"|"; }
9eaf1d2008-06-28Martin Nilsson  protected private string read()
f9322c1999-03-13Marcus Comstedt  { int i, st; string res=""; for (;;) { if (buf=="" && !more_data()) return 0; // eof sscanf(buf,"%*[ \t\r\n]%s",buf); if (buf=="") continue; if (buf[0]=='#') // comment, scan to newline { while ((i=search(buf,"\n"))<0) { // The rest of the buffer is comment, toss it and read more buf=""; if(!more_data()) return 0; // eof } buf=buf[i+1..]; continue; } break; } st = ::tell()-sizeof(buf); while ((i=search(buf, "\n"))<0) { if (!more_data()) return 0; // eof } while (buf[i-1]=='\\') { res+=buf[..i-2]; buf=buf[i+1..]; while (sscanf(buf,"%*[ \t\r]%s",buf)<2 || !sizeof(buf)) if (!more_data()) { buf = "";
334e872003-03-12Marcus Agehall  return res; // eof, or illegal... weird
f9322c1999-03-13Marcus Comstedt  } while ((i=search(buf, "\n"))<0) { if (!more_data()) return 0; // eof } } res+=buf[..i-1]; buf=buf[i+1..]; foreach(get_names(res), string name) if(!objectp(cache[name])) cache[name]=st; return res; }
9eaf1d2008-06-28Martin Nilsson  protected private string readat(int pos)
f9322c1999-03-13Marcus Comstedt  { rewind(pos); return read(); } array(string) _indices() { LOCK; if(!complete_index) { rewind(); while(read()); complete_index = 1; } UNLOCK; return sort(indices(cache)); }
3d0c502003-06-27Martin Nilsson  array(Termcap) _values()
f9322c1999-03-13Marcus Comstedt  { array(object|int) res = ({}); mapping(int:string) extra = ([]); LOCK; if (complete_index)
716c272006-01-07Martin Nilsson  res = predef::map(sort(indices(cache)), [function(string,mapping(int:string):Termcap)] lambda(string name, mapping(int:string) extra) { if (!objectp(cache[name]) && !extra[cache[name]]) extra[cache[name]] = readat(cache[name]); return cache[name]; }, extra);
f9322c1999-03-13Marcus Comstedt  else { array(string) resi = ({}); string cap; int i = 1; rewind(); while ((cap = read())) { array(string) names = get_names(cap); object|int o = objectp(cache[names[0]]) && cache[names[0]]; if (!o) { o = i++; extra[o] = cap; } res += ({ o }) * sizeof(names); resi += names; } sort(resi, res); complete_index = 1; } UNLOCK;
3d0c502003-06-27Martin Nilsson  return [array(Termcap)]
716c272006-01-07Martin Nilsson  predef::map(res, lambda(int|Termcap x, mapping(int:Termcap) y) {
c81a802007-04-06Henrik Grubbström (Grubba)  return objectp(x)? [object(Termcap)]x : y[x];
716c272006-01-07Martin Nilsson  }, mkmapping(indices(extra), predef::map(values(extra), Termcap, this)));
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected private string read_next(string find) // quick search
f9322c1999-03-13Marcus Comstedt  { for (;;) { int i, j; if (buf=="" && !more_data()) return 0; // eof i=search(buf,find); if (i!=-1) { int j=i; while (j>=0 && buf[j]!='\n') j--; // find backwards if (buf!="" && buf[j+1]!='#') // skip comments { buf=buf[j+1..]; return read(); } while ((i=search(buf,"\n",j+1))<0) if (!more_data()) return 0; // eof buf = buf[i+1..]; continue; } for(j=-1; (i=search(buf,"\n",j+1))>=0; j=i); buf = buf[j+1..]; if (!more_data()) return 0; // eof } }
3d0c502003-06-27Martin Nilsson  Termcap load(string term, int|void maxrecurse)
f9322c1999-03-13Marcus Comstedt  {
3d0c502003-06-27Martin Nilsson  int|string|Termcap cap;
f9322c1999-03-13Marcus Comstedt  LOCK; if (zero_type(cache[term])) { if (!complete_index) { rewind(); do cap = read_next(term); while(cap && search(get_names(cap), term)<0); } } else if (intp(cap=cache[term])) { rewind(cap); cap = read(); } UNLOCK; if (stringp(cap)) { array(string) names = get_names(cap);
3d0c502003-06-27Martin Nilsson  if ((cap = Termcap(cap, this, maxrecurse)))
f9322c1999-03-13Marcus Comstedt  { LOCK; foreach(names, string name)
c83fb62000-03-30Henrik Grubbström (Grubba)  cache[name] = [object(Termcap)]cap;
f9322c1999-03-13Marcus Comstedt  UNLOCK; } }
c83fb62000-03-30Henrik Grubbström (Grubba)  return objectp(cap) && [object(Termcap)]cap;
f9322c1999-03-13Marcus Comstedt  }
3d0c502003-06-27Martin Nilsson  Termcap `[](string name)
f9322c1999-03-13Marcus Comstedt  { return load(name); } }
fbb2252010-06-05Henrik Grubbström (Grubba) //! Terminfo database for a single directory.
f9322c1999-03-13Marcus Comstedt class TerminfoDB { MUTEX
9eaf1d2008-06-28Martin Nilsson  protected private string dir; protected private mapping(string:Terminfo) cache = ([]); protected private int complete_index=0;
f9322c1999-03-13Marcus Comstedt 
fbb2252010-06-05Henrik Grubbström (Grubba)  protected string _sprintf() { return sprintf("Stdio.Terminfo.TerminfoDB(%O)", dir); } protected void create(string|void dirname)
f9322c1999-03-13Marcus Comstedt  { if (!dirname) {
fbb2252010-06-05Henrik Grubbström (Grubba)  // This is retained for compat. // Typical initialization is now via MetaTerminfoDB.
a85c342003-12-10Henrik Grubbström (Grubba)  foreach (({"/usr/share/lib/terminfo", "/usr/share/terminfo", "/usr/share/termcap",
fbb2252010-06-05Henrik Grubbström (Grubba)  "/usr/lib/terminfo", "/usr/share/misc/terminfo", "/lib/terminfo", "/etc/terminfo" }), string dn)
f9322c1999-03-13Marcus Comstedt  {
61a4242000-08-27Mirar (Pontus Hagland)  .Stat s = file_stat(dn); if (s && s->type=="dir")
f9322c1999-03-13Marcus Comstedt  { dirname = dn; break; } } if (!dirname) {
3d0c502003-06-27Martin Nilsson  destruct(this);
f9322c1999-03-13Marcus Comstedt  return; } } if(sizeof(dirname)<1 || dirname[-1]!='/') dirname += "/"; if (!get_dir(dir = dirname)) error("failed to read terminfo dir %O\n", dirname); } array(string) _indices() { LOCK; if (!complete_index) { foreach (get_dir(dir), string a) if (sizeof(a) == 1) foreach (get_dir(dir+a), string b) if(zero_type(cache[b])) cache[b] = 0; complete_index = 1; } UNLOCK; return sort(indices(cache)); } array(object) _values() {
716c272006-01-07Martin Nilsson  return predef::map(_indices(), [function(string:object(Terminfo))] lambda(string name) { return cache[name] || Terminfo(dir+name[..0]+"/"+name); });
f9322c1999-03-13Marcus Comstedt  }
3d0c502003-06-27Martin Nilsson  Terminfo load(string term)
f9322c1999-03-13Marcus Comstedt  {
3d0c502003-06-27Martin Nilsson  Terminfo ti;
f9322c1999-03-13Marcus Comstedt 
ead9722003-01-20Martin Nilsson  if (!sizeof(term))
f9322c1999-03-13Marcus Comstedt  return 0; LOCK; if (!(ti = cache[term])) {
a85c342003-12-10Henrik Grubbström (Grubba)  if (file_stat(dir+term[..0]+"/"+term)) { // Traditional Terminfo layout.
f9322c1999-03-13Marcus Comstedt  ti = Terminfo(dir+term[..0]+"/"+term);
a85c342003-12-10Henrik Grubbström (Grubba)  } else if (file_stat(sprintf("%s%02x/%s", dir, term[0], term))) { // MacOS X Terminfo layout. ti = Terminfo(sprintf("%s%02x/%s", dir, term[0], term)); }
f9322c1999-03-13Marcus Comstedt  if (ti) cache[term] = ti; } UNLOCK; return ti; }
3d0c502003-06-27Martin Nilsson  Terminfo `[](string name)
f9322c1999-03-13Marcus Comstedt  { return load(name); } }
fbb2252010-06-05Henrik Grubbström (Grubba) //! @[TerminfoDB] that merges several directorys. class MetaTerminfoDB { protected array(TerminfoDB) dbs = ({}); //! Create a new Meta @[TerminfoDB]. //! //! @param dbs //! Array with elements in priority order. Elements may be either //! @mixed //! @type TerminfoDB //! An active @[TerminfoDB]. //! @type string //! A directory that may exist and contain a terminfo database.
0caabf2010-06-22Martin Nilsson  //! @endmixed
fbb2252010-06-05Henrik Grubbström (Grubba)  //! //! @returns //! If the resulting set of @[TerminfoDB]'s is empty, //! the object will be destructed. protected void create(array(TerminfoDB|string)|void dbs) { if (!dbs) { // Terminfo locations in priority order. dbs = ({ // Local terminfo. "/etc/terminfo", // Operating System terminfo. "/lib/terminfo", "/usr/lib/terminfo", // Extra terminfo. These are often symlinks to the above. "/usr/share/lib/terminfo", "/usr/share/terminfo", "/usr/share/termcap", "/usr/share/misc/terminfo", }); } foreach(dbs, string|TerminfoDB db) { if (stringp(db)) { .Stat st = file_stat(db); if (!st || !st->isdir) continue; db = TerminfoDB(db); } if (!db) continue; this_program::dbs += ({ db }); } // werror("TerminfoDBs: %O\n", this_program::dbs); if (!sizeof(this_program::dbs)) { destruct(this); } } Terminfo `[](string name) { foreach(dbs, TerminfoDB db) { Terminfo ti = db[name]; if (ti) return ti; } return 0; } }
9eaf1d2008-06-28Martin Nilsson protected private Termcap defterm; protected private TermcapDB deftermcap;
fbb2252010-06-05Henrik Grubbström (Grubba) protected private MetaTerminfoDB defterminfo;
f9322c1999-03-13Marcus Comstedt 
3d0c502003-06-27Martin Nilsson TermcapDB defaultTermcapDB()
f9322c1999-03-13Marcus Comstedt {
3d0c502003-06-27Martin Nilsson  TermcapDB tcdb;
f9322c1999-03-13Marcus Comstedt  LOCK;
e6f49b1999-03-23Marcus Comstedt  catch { tcdb = deftermcap || (deftermcap = TermcapDB()); };
f9322c1999-03-13Marcus Comstedt  UNLOCK; return tcdb; }
fbb2252010-06-05Henrik Grubbström (Grubba) MetaTerminfoDB defaultTerminfoDB()
f9322c1999-03-13Marcus Comstedt {
fbb2252010-06-05Henrik Grubbström (Grubba)  MetaTerminfoDB tidb;
f9322c1999-03-13Marcus Comstedt  LOCK;
fbb2252010-06-05Henrik Grubbström (Grubba)  catch { tidb = defterminfo || (defterminfo = MetaTerminfoDB()); };
f9322c1999-03-13Marcus Comstedt  UNLOCK; return tidb; }
6c00e02001-10-23Martin Nilsson //! Returns the terminal description object for @[term] from the //! systems termcap database. Returns 0 if not found. //! //! @seealso //! Stdio.Terminfo.getTerm, Stdio.Terminfo.getTerminfo
3d0c502003-06-27Martin Nilsson Termcap getTermcap(string term)
f9322c1999-03-13Marcus Comstedt {
3d0c502003-06-27Martin Nilsson  TermcapDB tcdb = defaultTermcapDB();
f9322c1999-03-13Marcus Comstedt  return tcdb && tcdb[term]; }
6c00e02001-10-23Martin Nilsson //! Returns the terminal description object for @[term] from the //! systems terminfo database. Returns 0 if not found. //! //! @seealso //! Stdio.Terminfo.getTerm, Stdio.Terminfo.getTermcap
3d0c502003-06-27Martin Nilsson Terminfo getTerminfo(string term)
f9322c1999-03-13Marcus Comstedt {
3d0c502003-06-27Martin Nilsson  TerminfoDB tidb = defaultTerminfoDB();
f9322c1999-03-13Marcus Comstedt  return tidb && tidb[term]; }
6c00e02001-10-23Martin Nilsson //! Returns an object describing the terminal term. If term is not specified, it will //! default to @[getenv("TERM")] or if that fails to "dumb". //! //! Lookup of terminal information will first be done in the systems terminfo //! database, and if that fails in the termcap database. If neither database exists, a //! hardcoded entry for "dumb" will be used. //! //! @seealso //! Stdio.Terminfo.getTerminfo, Stdio.Terminfo.getTermcap, Stdio.getFallbackTerm
3d0c502003-06-27Martin Nilsson Termcap getTerm(string|void term)
f9322c1999-03-13Marcus Comstedt { if (!term) {
3d0c502003-06-27Martin Nilsson  Termcap t = defterm;
f9322c1999-03-13Marcus Comstedt  if (!t) {
c83fb62000-03-30Henrik Grubbström (Grubba)  string tc = [string]getenv("TERMCAP");
791c512002-10-25Jonas Wallden  if (mixed err = catch { t = tc && sizeof(tc) && tc[0] != '/' && Termcap(tc); }) werror("%s", describe_backtrace(err)); if (!t) t = getTerm(getenv("TERM") || "dumb");
f9322c1999-03-13Marcus Comstedt  LOCK; if (!defterm) defterm = t; UNLOCK; } return t; }
dff4e41999-03-18Marcus Comstedt  return getTerminfo(term) || getTermcap(term) || getFallbackTerm(term); }
6c00e02001-10-23Martin Nilsson //! Returns an object describing the fallback terminal for the terminal //! @[term]. This is usually equvivalent to @[Stdio.Terminfo.getTerm("dumb")]. //! //! @seealso //! Stdio.Terminfo.getTerm
9eaf1d2008-06-28Martin Nilsson protected Termcap getFallbackTerm(string term)
dff4e41999-03-18Marcus Comstedt { return (term=="dumb"? Termcap("dumb:\\\n\t:am:co#80:do=^J:") : getTerm("dumb"));
f9322c1999-03-13Marcus Comstedt }
fa34962003-06-02Martin Stjernholm 
9eaf1d2008-06-28Martin Nilsson protected int is_tty_cache;
fa34962003-06-02Martin Stjernholm  int is_tty() //! Returns 1 if @[Stdio.stdin] is connected to an interactive //! terminal that can handle backspacing, carriage return without //! linefeed, and the like. { if(!is_tty_cache) { #ifdef __NT__ is_tty_cache=1; #else
3d0c502003-06-27Martin Nilsson  is_tty_cache=!!.stdin->tcgetattr();
fa34962003-06-02Martin Stjernholm #endif if(!is_tty_cache) { is_tty_cache=-1; }else{ switch(getenv("TERM")) { case "dumb": case "emacs": is_tty_cache=-1; } } } return is_tty_cache>0; }