d65ca91999-01-30Henrik Grubbström (Grubba) // $Id: Stdio.pmod,v 1.37 1999/01/30 01:35:08 grubba 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;
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  mixed ___read_oob_callback; mixed ___write_oob_callback; #endif mixed ___id;
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG string __closed_backtrace;
41a8b01998-09-01Fredrik Hübinette (Hubbe) #define CHECK_OPEN() \ if(!_fd) \ { \ throw(({ \ "Stdio.File(): line "+__LINE__+" on closed file.\n"+ \ (__closed_backtrace ? \ sprintf("File was closed from:\n %-=200s\n",__closed_backtrace) : \ "This file has never been open.\n" ), \ backtrace()})); \ \ } #else #define CHECK_OPEN()
35dd981998-07-18Fredrik Hübinette (Hubbe) #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();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
c46feb1998-04-05Fredrik Hübinette (Hubbe)  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();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
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();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
c46feb1998-04-05Fredrik Hübinette (Hubbe)  return ::connect(host,port); }
d65ca91999-01-30Henrik Grubbström (Grubba)  static private function(int, mixed ...:void) _async_cb; static private array(mixed) _async_args; static private void _async_connected(mixed|void ignored) { // Copy the args to avoid races. function(int, mixed ...:void) cb = _async_cb; array(mixed) args = _async_args; _async_cb = 0; _async_args = 0; set_nonblocking(0,0,0); cb(1, @args); } static private void _async_failed(mixed|void ignored) { // Copy the args to avoid races. function(int, mixed ...:void) cb = _async_cb; array(mixed) args = _async_args; _async_cb = 0; _async_args = 0; set_nonblocking(0,0,0); cb(0, @args); } // NOTE: Zaps nonblocking-state. int async_connect(string host, int port, function(int, mixed ...:void) callback, mixed ... args) { if (!_fd && !open_socket()) { // Out of sockets? return 0; } _async_cb = callback; _async_args = args; set_nonblocking(0, _async_connected, _async_failed); mixed err; if (err = catch(connect(host, port))) { // Illegal format. -- Bad hostname? set_nonblocking(0,0,0); throw(err); } return(1); // OK so far. }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  object(File) pipe(void|int how) { _fd=Fd();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
c46feb1998-04-05Fredrik Hübinette (Hubbe)  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;
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
217a001998-04-14Fredrik Hübinette (Hubbe)  case 0: break; case "stdout":
393ebe1998-04-15Fredrik Hübinette (Hubbe)  _fd=_stdout;
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
217a001998-04-14Fredrik Hübinette (Hubbe)  break; case "stderr": _fd=_stderr;
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
217a001998-04-14Fredrik Hübinette (Hubbe)  break; default: _fd=Fd();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
217a001998-04-14Fredrik Hübinette (Hubbe)  if(query_num_arg()<3) bits=0666; ::open(file,mode,bits);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } }
0a970a1998-07-26Fredrik Hübinette (Hubbe)  int assign(object o)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
0a970a1998-07-26Fredrik Hübinette (Hubbe)  if((program)Fd == (program)object_program(o))
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
0a970a1998-07-26Fredrik Hübinette (Hubbe)  _fd = o->dup();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }else{
0a970a1998-07-26Fredrik Hübinette (Hubbe)  _fd = o->_fd; if(___read_callback = o->___read_callback) _fd->_read_callback=__stdio_read_callback; if(___write_callback = o->___write_callback) _fd->_write_callback=__stdio_write_callback; ___close_callback = o->___close_callback;
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
0a970a1998-07-26Fredrik Hübinette (Hubbe)  if(___read_oob_callback = o->___read_oob_callback)
a050711998-10-22Henrik Grubbström (Grubba)  _fd->_read_oob_callback = __stdio_read_oob_callback;
0a970a1998-07-26Fredrik Hübinette (Hubbe)  if(___write_oob_callback = o->___write_oob_callback)
a050711998-10-22Henrik Grubbström (Grubba)  _fd->_write_oob_callback = __stdio_write_oob_callback;
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif
0a970a1998-07-26Fredrik Hübinette (Hubbe)  ___id = o->___id;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } return 0; }
c158fe1998-04-10Henrik Grubbström (Grubba)  object dup() {
0a970a1998-07-26Fredrik Hübinette (Hubbe)  object to = File(); to->_fd = _fd; if(to->___read_callback = ___read_callback) _fd->_read_callback=to->__stdio_read_callback; if(to->___write_callback = ___write_callback) _fd->_write_callback=to->__stdio_write_callback; to->___close_callback = ___close_callback;
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
0a970a1998-07-26Fredrik Hübinette (Hubbe)  if(to->___read_oob_callback = ___read_oob_callback) _fd->_read_oob_callback=to->__stdio_read_oob_callback; if(to->___write_oob_callback = ___write_oob_callback) _fd->_write_oob_callback=to->__stdio_write_oob_callback; #endif to->___id = ___id; return to;
c158fe1998-04-10Henrik Grubbström (Grubba)  }
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)  }
0a970a1998-07-26Fredrik Hübinette (Hubbe)  static void __stdio_read_callback()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
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);
bbc6b71998-10-22Henrik Grubbström (Grubba)  if (___close_callback) { ___close_callback(___id); }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } }
0a970a1998-07-26Fredrik Hübinette (Hubbe)  static void __stdio_write_callback() { ___write_callback(___id); }
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
0a970a1998-07-26Fredrik Hübinette (Hubbe)  static void __stdio_read_oob_callback()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  { string s=::read_oob(8192,1); if(s && strlen(s)) { ___read_oob_callback(___id, s); }else{
bbc6b71998-10-22Henrik Grubbström (Grubba)  ::set_read_oob_callback(0); if (___close_callback) { ___close_callback(___id); }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } }
0a970a1998-07-26Fredrik Hübinette (Hubbe)  static void __stdio_write_oob_callback() { ___write_oob_callback(___id); }
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif
0a970a1998-07-26Fredrik Hübinette (Hubbe) #define SET(X,Y) ::set_##X ((___##X = (Y)) && __stdio_##X)
bbe0a51998-07-28Fredrik Hübinette (Hubbe) #define _SET(X,Y) _fd->_##X=(___##X = (Y)) && __stdio_##X
217a001998-04-14Fredrik Hübinette (Hubbe) 
c158fe1998-04-10Henrik Grubbström (Grubba) #define CBFUNC(X) \ void set_##X (mixed l##X) \ { \
41a8b01998-09-01Fredrik Hübinette (Hubbe)  CHECK_OPEN(); \
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)
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  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,
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  mixed|void roobcb, mixed|void woobcb #endif ) {
41a8b01998-09-01Fredrik Hübinette (Hubbe)  CHECK_OPEN();
0a970a1998-07-26Fredrik Hübinette (Hubbe)  ::_disable_callbacks(); // Thread safing _SET(read_callback,rcb); _SET(write_callback,wcb);
217a001998-04-14Fredrik Hübinette (Hubbe)  ___close_callback=ccb;
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__HAVE_OOB__)
0a970a1998-07-26Fredrik Hübinette (Hubbe)  _SET(read_oob_callback,roobcb); _SET(write_oob_callback,woobcb);
c46feb1998-04-05Fredrik Hübinette (Hubbe) #endif
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG if(mixed x=catch { ::set_nonblocking(); }) { x[0]+=(__closed_backtrace ? sprintf("File was closed from:\n %-=200s\n",__closed_backtrace) : "This file has never been open.\n" )+ (_fd?"_fd is nonzero\n":"_fd is zero\n"); throw(x); } #else
c46feb1998-04-05Fredrik Hübinette (Hubbe)  ::set_nonblocking();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #endif ::_enable_callbacks();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } void set_blocking() {
41a8b01998-09-01Fredrik Hübinette (Hubbe)  CHECK_OPEN();
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_callback,0); SET(write_callback,0); ___close_callback=0;
a050711998-10-22Henrik Grubbström (Grubba) #if constant(files.__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