35dd981998-07-18Fredrik Hübinette (Hubbe) // $Id: Stdio.pmod,v 1.30 1998/07/19 03:24:09 hubbe Exp $
8458bc1998-07-15Henrik Grubbström (Grubba) 
c2a4061997-02-06Fredrik Hübinette (Hubbe) #include <string.h>
6d22541998-01-28Fredrik Hübinette (Hubbe) inherit files;
c46feb1998-04-05Fredrik Hübinette (Hubbe) class File { inherit Fd_ref; mixed ___read_callback; mixed ___write_callback; mixed ___close_callback; #if constant(__HAVE_OOB__)_ mixed ___read_oob_callback; mixed ___write_oob_callback; #endif mixed ___id;
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG string __closed_backtrace; #endif
2f55e91998-05-27Fredrik Hübinette (Hubbe)  int errno() { return _fd && ::errno(); }
217a001998-04-14Fredrik Hübinette (Hubbe)  int open(string file, string mode, void|int bits)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  { _fd=Fd(); if(query_num_arg()<3) bits=0666; return ::open(file,mode,bits); }
feaa7e1998-04-06Henrik Grubbström (Grubba)  int open_socket(int|void port, string|void address)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  { _fd=Fd();
0ec14c1998-04-06Henrik Grubbström (Grubba)  switch(query_num_arg()) { case 0: return ::open_socket(); case 1: return ::open_socket(port); default: return ::open_socket(port, address); }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } int connect(string host, int port) { if(!_fd) _fd=Fd(); return ::connect(host,port); } object(File) pipe(void|int how) { _fd=Fd(); if(query_num_arg()==0) how=PROP_NONBLOCK | PROP_BIDIRECTIONAL; if(object(Fd) fd=::pipe(how)) { object o=File(); o->_fd=fd; return o; }else{ return 0; } }
217a001998-04-14Fredrik Hübinette (Hubbe)  void create(string|void file,void|string mode,void|int bits)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
217a001998-04-14Fredrik Hübinette (Hubbe)  switch(file)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
217a001998-04-14Fredrik Hübinette (Hubbe)  case "stdin": _fd=_stdin; case 0: break; case "stdout":
393ebe1998-04-15Fredrik Hübinette (Hubbe)  _fd=_stdout;
217a001998-04-14Fredrik Hübinette (Hubbe)  break; case "stderr": _fd=_stderr; break; default: _fd=Fd(); if(query_num_arg()<3) bits=0666; ::open(file,mode,bits);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } }
c158fe1998-04-10Henrik Grubbström (Grubba)  // Don't allow overloading of this function. static private nomask int do_assign(object to, object from)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  { if((program)Fd == (program)object_program(from)) {
c158fe1998-04-10Henrik Grubbström (Grubba)  to->_fd = from->dup();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }else{
c158fe1998-04-10Henrik Grubbström (Grubba)  to->_fd = from->_fd; to->___read_callback = from->___read_callback; to->___write_callback = from->___write_callback; to->___close_callback = from->___close_callback;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #if constant(__HAVE_OOB__)_
c158fe1998-04-10Henrik Grubbström (Grubba)  to->___read_oob_callback = from->___read_oob_callback; to->___write_oob_callback = from->___write_oob_callback;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif
c158fe1998-04-10Henrik Grubbström (Grubba)  to->___id = from->___id;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } return 0; } int assign(object o) { return do_assign(this_object(), o); }
c158fe1998-04-10Henrik Grubbström (Grubba)  object dup() { object o; o = File(); do_assign(o, this_object()); return o; }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  int close(void|string how) {
c158fe1998-04-10Henrik Grubbström (Grubba)  if(::close(how||"rw"))
35dd981998-07-18Fredrik Hübinette (Hubbe)  {
c158fe1998-04-10Henrik Grubbström (Grubba)  _fd=0;
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=master()->describe_backtrace(backtrace()); #endif }
c158fe1998-04-10Henrik Grubbström (Grubba)  return 1;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #if 0 if(how) { if(::close(how)) _fd=0; }else{ _fd=0; } #endif } static void my_read_callback() {
a509d51998-07-08Fredrik Hübinette (Hubbe) #if defined(__STDIO_DEBUG) && !defined(__NT__) if(!::peek()) throw( ({"Read callback with no data to read!\n",backtrace()}) ); #endif
c46feb1998-04-05Fredrik Hübinette (Hubbe)  string s=::read(8192,1); if(s && strlen(s)) { ___read_callback(___id, s); }else{
27f05a1998-04-06Fredrik Hübinette (Hubbe)  ::set_read_callback(0);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  ___close_callback(___id); } } static void my_write_callback() { ___write_callback(___id); } #if constant(__HAVE_OOB__)_ static void my_read_oob_callback() { string s=::read_oob(8192,1); if(s && strlen(s)) { ___read_oob_callback(___id, s); }else{ ___close_callback(___id); } } static void my_write_oob_callback() { ___write_oob_callback(___id); } #endif
217a001998-04-14Fredrik Hübinette (Hubbe) #define SET(X,Y) ::set_##X ((___##X = (Y)) && my_##X)
c158fe1998-04-10Henrik Grubbström (Grubba) #define CBFUNC(X) \ void set_##X (mixed l##X) \ { \
217a001998-04-14Fredrik Hübinette (Hubbe)  SET( X , l##X ); \
c158fe1998-04-10Henrik Grubbström (Grubba)  } \ \ mixed query_##X () \ { \ return ___##X; \
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } CBFUNC(read_callback) CBFUNC(write_callback) #if constant(__HAVE_OOB__)_ CBFUNC(read_oob_callback) CBFUNC(write_oob_callback) #endif mixed query_close_callback() { return ___close_callback; }
217a001998-04-14Fredrik Hübinette (Hubbe)  mixed set_close_callback(mixed c) { ___close_callback=c; }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  void set_id(mixed i) { ___id=i; }
7694021998-04-06Fredrik Hübinette (Hubbe)  mixed query_id() { return ___id; }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  void set_nonblocking(mixed|void rcb, mixed|void wcb, mixed|void ccb, #if constant(__HAVE_OOB__)_ mixed|void roobcb, mixed|void woobcb #endif ) {
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG if(!_fd) { throw(({ "Stdio.File(): set_nonblocking on closed file.\n"+ (__closed_backtrace ? sprintf("File was closed from:\n %-=200s\n",__closed_backtrace) : "This file has never been open.\n" ), backtrace()})); } #endif
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_callback,rcb); SET(write_callback,wcb); ___close_callback=ccb;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #if constant(__HAVE_OOB__)_
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_oob_callback,roobcb); SET(write_oob_callback,woobcb);
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif ::set_nonblocking(); } void set_blocking() {
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_callback,0); SET(write_callback,0); ___close_callback=0;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #if constant(__HAVE_OOB__)_
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_oob_callback,0); SET(write_oob_callback,0);
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif ::set_blocking(); } }; class Port {
36bff11998-05-27Henrik Grubbström (Grubba)  inherit _port;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  object(File) accept() { if(object x=::accept()) {
36bff11998-05-27Henrik Grubbström (Grubba)  object(File) y=File();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  y->_fd=x; return y; } return 0; } }
58fcd51998-01-27Fredrik Hübinette (Hubbe) 
c2a4061997-02-06Fredrik Hübinette (Hubbe) object stderr=File("stderr"); object stdout=File("stdout"); #define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) ) class FILE { #define BUFSIZE 16384 inherit File : file; /* Private functions / buffers etc. */ private string b=""; private int bpos=0; inline private static nomask int get_data() { string s; b = b[bpos .. ]; bpos=0; s = file::read(BUFSIZE,1); if(!s || !strlen(s)) return 0; b += s; return 1; } inline private static nomask string extract(int bytes, int|void skip) { string s; s=b[bpos..bpos+bytes-1]; bpos += bytes+skip; return s; } /* Public functions. */ string gets() {
b6f2fb1997-05-03Fredrik Hübinette (Hubbe)  int p,tmp=0; while((p=search(b, "\n", bpos+tmp)) == -1)
5ae2381997-03-16Fredrik Hübinette (Hubbe)  {
b6f2fb1997-05-03Fredrik Hübinette (Hubbe)  tmp=strlen(b)-bpos;
5ae2381997-03-16Fredrik Hübinette (Hubbe)  if(!get_data()) return 0; }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return extract(p-bpos, 1); } int seek(int pos) { bpos=0; b=""; return file::seek(pos); }
2eedf71997-05-16Wilhelm Köhler  int tell() {
0328781998-03-24Marcus Comstedt  return file::tell()-sizeof(b)+bpos;
2eedf71997-05-16Wilhelm Köhler  }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  int close(void|string mode) { bpos=0; b=""; if(!mode) mode="rw"; file::close(mode); } int open(string file, void|string mode) { bpos=0; b=""; if(!mode) mode="rwc"; return file::open(file,mode); } int open_socket() { bpos=0; b=""; return file::open_socket(); } object pipe() { bpos=0; b=""; return file::pipe(); }
54dd9b1997-04-10Fredrik Hübinette (Hubbe)  int assign(object foo) { bpos=0; b=""; return ::assign(foo); }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  object(FILE) dup() { object(FILE) o=FILE(); o->assign(this_object()); return o; }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  void set_nonblocking() { error("Cannot use nonblocking IO with buffered files.\n"); } int printf(string fmt, mixed ... data) { if(!sizeof(data)) return file::write(fmt); else return file::write(sprintf(fmt,@data)); }
7543bf1998-06-28Henrik Grubbström (Grubba)  string read(int|void bytes)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
7543bf1998-06-28Henrik Grubbström (Grubba)  if (!query_num_arg()) { bytes = 0x7fffffff; }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  while(strlen(b) - bpos < bytes)
7543bf1998-06-28Henrik Grubbström (Grubba)  if(!get_data()) { // EOF. string res = b[bpos..]; b = ""; bpos = 0; return res; }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return extract(bytes); } string ungets(string s) { b=s+b[bpos..]; bpos=0; } int getchar() { if(strlen(b) - bpos < 1) if(!get_data()) return -1; return b[bpos++]; } };
e965921997-07-02Henrik Grubbström (Grubba) object(FILE) stdin=FILE("stdin");
c2a4061997-02-06Fredrik Hübinette (Hubbe)  string read_file(string filename,void|int start,void|int len) {
e965921997-07-02Henrik Grubbström (Grubba)  object(FILE) f; string ret, tmp;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  f=FILE(); if(!f->open(filename,"r")) return 0;
af72c61998-01-17Henrik Grubbström (Grubba)  // Disallow devices and directories. array st; if (f->stat && (st = f->stat()) && (st[1] < 0)) { throw(({ sprintf("Stdio.read_file(): File \"%s\" is not a regular file!\n", filename), backtrace() })); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  switch(query_num_arg()) { case 1: ret=f->read(0x7fffffff); break; case 2: len=0x7fffffff; case 3: while(start-- && f->gets());
e965921997-07-02Henrik Grubbström (Grubba)  object(String_buffer) buf=String_buffer();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  while(len-- && (tmp=f->gets())) { buf->append(tmp); buf->append("\n"); } ret=buf->get_buffer(); destruct(buf); } destruct(f); return ret; } string read_bytes(string filename,void|int start,void|int len) { string ret;
e965921997-07-02Henrik Grubbström (Grubba)  object(File) f = File(); if(!f->open(filename,"r"))
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return 0;
af72c61998-01-17Henrik Grubbström (Grubba)  // Disallow devices and directories. array st; if (f->stat && (st = f->stat()) && (st[1] < 0)) { throw(({sprintf("Stdio.read_bytes(): File \"%s\" is not a regular file!\n", filename), backtrace() })); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  switch(query_num_arg()) { case 1: case 2: len=0x7fffffff; case 3:
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  if(start) f->seek(start);
c2a4061997-02-06Fredrik Hübinette (Hubbe)  }
e965921997-07-02Henrik Grubbström (Grubba)  ret=f->read(len); f->close();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return ret; } int write_file(string filename,string what) { int ret;
e965921997-07-02Henrik Grubbström (Grubba)  object(File) f = File(); if(!f->open(filename,"awc"))
c2a4061997-02-06Fredrik Hübinette (Hubbe)  error("Couldn't open file "+filename+".\n");
e965921997-07-02Henrik Grubbström (Grubba)  ret=f->write(what); f->close();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return ret; } int file_size(string s) { int *stat; stat=file_stat(s); if(!stat) return -1; return stat[1]; } void perror(string s) { #if efun(strerror) stderr->write(s+": "+strerror(predef::errno())+"\n"); #else stderr->write(s+": errno: "+predef::errno()+"\n"); #endif }
5ae2381997-03-16Fredrik Hübinette (Hubbe)  mixed `[](string index) { mixed x=`->(this_object(),index); if(x) return x; switch(index) { case "readline": return master()->resolv("readline"); default: return ([])[0]; } }
8d49101998-01-21Fredrik Hübinette (Hubbe)  #if constant(system.cp) constant cp=system.cp; #else #define BLOCK 65536 int cp(string from, string to) { string data; object tmp=File();
6463921998-07-14Fredrik Hübinette (Hubbe)  if(!tmp->open(from,"r")) return 0;
8d49101998-01-21Fredrik Hübinette (Hubbe)  function r=tmp->read; tmp=File();
6463921998-07-14Fredrik Hübinette (Hubbe)  if(!tmp->open(to,"wct")) return 0;
8d49101998-01-21Fredrik Hübinette (Hubbe)  function w=tmp->write; do { data=r(BLOCK); if(!data) return 0; if(w(data)!=strlen(data)) return 0; }while(strlen(data) == BLOCK); return 1; } #endif