a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
59db4f2013-06-11Martin Nilsson inherit _Stdio;
6d22541998-01-28Fredrik Hübinette (Hubbe) 
6aeeab2001-12-04Martin Nilsson #ifdef SENDFILE_DEBUG
a8852e2004-04-06Henrik Grubbström (Grubba) #define SF_WERR(X) werror("Stdio.sendfile(): %s\n", X)
6aeeab2001-12-04Martin Nilsson #else #define SF_WERR(X) #endif
a8852e2004-04-06Henrik Grubbström (Grubba) //#define BACKEND_DEBUG #ifdef BACKEND_DEBUG
51f1ce2015-09-06Martin Nilsson #define BE_WERR(X ...) werror("FD %O: %s\n", _fd, sprintf(X))
a8852e2004-04-06Henrik Grubbström (Grubba) #else
51f1ce2015-09-06Martin Nilsson #define BE_WERR(X ...)
a8852e2004-04-06Henrik Grubbström (Grubba) #endif
ba6d7b2001-04-19Martin Stjernholm // TRACK_OPEN_FILES is a debug tool to track down where a file is // currently opened from (see report_file_open_places). It's used // primarily when debugging on NT since an opened file can't be // renamed or removed there. #ifndef TRACK_OPEN_FILES #define register_open_file(file, id, backtrace) #define register_close_file(id) #endif
bbbae52011-11-05Martin Nilsson constant LineIterator = __builtin.file_line_iterator;
91882a2005-10-17Martin Nilsson 
66fe2a2009-12-03Martin Stjernholm final constant DATA_CHUNK_SIZE = 64 * 1024; //! Size used in various places to divide incoming or outgoing data //! into chunks.
5729ec2000-12-28Henrik Grubbström (Grubba) //! The Stdio.Stream API. //! //! This class exists purely for typing reasons. //!
07d9352014-09-05Per Hedbor //! Use in types in place of @[Stdio.File] where only blocking //! stream-oriented I/O is done with the object. //! //! This class lists the minimum functionality guaranteed to exist in //! all Stream objects.
5729ec2000-12-28Henrik Grubbström (Grubba) //! //! @seealso //! @[NonblockingStream], @[BlockFile], @[File], @[FILE] //!
7e9fcc1999-12-13Per Hedbor class Stream {
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  string read(int nbytes);
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  int write(string data);
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  void close();
07d9352014-09-05Per Hedbor  //!
5729ec2000-12-28Henrik Grubbström (Grubba)  optional string read_oob(int nbytes); optional int write_oob(string data);
60772e2008-12-09Henrik Grubbström (Grubba)  optional mapping(string:int) tcgetattr(); optional int tcsetattr(mapping(string:int) attr, string|void when);
7e9fcc1999-12-13Per Hedbor }
60772e2008-12-09Henrik Grubbström (Grubba) //! Argument to @[Stdio.File()->tcsetattr()]. //! //! Change immediately. constant TCSANOW = "TCSANOW"; //! Argument to @[Stdio.File()->tcsetattr()]. //! //! Change after all output has been written. constant TCSADRAIN = "TCSADRAIN"; //! Argument to @[Stdio.File()->tcsetattr()]. //! //! Change after all output has been written, //! and empty the input buffers. constant TCSAFLUSH = "TCSAFLUSH";
5729ec2000-12-28Henrik Grubbström (Grubba) //! The Stdio.NonblockingStream API. //! //! This class exists purely for typing reasons. //!
07d9352014-09-05Per Hedbor //! Use in types in place of @[Stdio.File] where nonblocking and/or //! blocking stream-oriented I/O is done with the object. //!
5729ec2000-12-28Henrik Grubbström (Grubba) //! @seealso //! @[Stream], @[BlockFile], @[File], @[FILE] //!
7e9fcc1999-12-13Per Hedbor class NonblockingStream { inherit Stream;
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  NonblockingStream set_read_callback( function f, mixed ... rest ); NonblockingStream set_write_callback( function f, mixed ... rest ); NonblockingStream set_close_callback( function f, mixed ... rest );
ca6bd02012-05-01Bill Welliver  NonblockingStream set_fs_event_callback( function f, int event_mask, mixed ... rest );
7e9fcc1999-12-13Per Hedbor 
07d9352014-09-05Per Hedbor  //!
60772e2008-12-09Henrik Grubbström (Grubba)  optional NonblockingStream set_read_oob_callback(function f, mixed ... rest)
7e9fcc1999-12-13Per Hedbor  { error("OOB not implemented for this stream type\n"); }
60772e2008-12-09Henrik Grubbström (Grubba)  optional NonblockingStream set_write_oob_callback(function f, mixed ... rest)
7e9fcc1999-12-13Per Hedbor  { error("OOB not implemented for this stream type\n"); }
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  void set_nonblocking( function a, function b, function c, function|void d, function|void e);
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  void set_blocking(); }
5729ec2000-12-28Henrik Grubbström (Grubba) //! The Stdio.BlockFile API. //! //! This class exists purely for typing reasons. //! //! Use in types in place of @[Stdio.File] where only blocking //! I/O is done with the object.
07d9352014-09-05Per Hedbor //!
5729ec2000-12-28Henrik Grubbström (Grubba) //! @seealso //! @[Stream], @[NonblockingStream], @[File], @[FILE] //!
7e9fcc1999-12-13Per Hedbor class BlockFile { inherit Stream;
07d9352014-09-05Per Hedbor  //!
707b922014-09-23Per Hedbor  int seek(int to, string|void how);
07d9352014-09-05Per Hedbor  //!
7e9fcc1999-12-13Per Hedbor  int tell(); }
30204c2014-10-04Henrik Grubbström (Grubba) //! The various read_callback signatures. //! //! The string (or void) version is used when buffer mode (see //! @[set_buffer_mode]) has not been enabled for reading. //!
0f9a9a2015-03-21Henrik Grubbström (Grubba) //! The @[Buffer] version is used when a @[Buffer] has been enabled //! for reading.
30204c2014-10-04Henrik Grubbström (Grubba) //! //! In both cases the data is the newly arrived data, but in buffered //! mode data you did not fully read in the last read callback is //! kept in the buffer. local typedef function(mixed|void,string:int|void)| function(mixed|void,Buffer:int|void)| function(mixed|void:int|void) read_callback_t; //! The various write_callback signatures. //! //! The void version is used when buffer mode (see //! @[set_buffer_mode]) has not been enabled for writing. //!
0f9a9a2015-03-21Henrik Grubbström (Grubba) //! The @[Buffer] version is used when a @[Buffer] has been enabled //! for writing, add data to that buffer to send it.
30204c2014-10-04Henrik Grubbström (Grubba) local typedef function(mixed|void:int|void) | function(mixed|void,Buffer:int|void) write_callback_t;
3bc55b2003-10-29Martin Stjernholm //! This is the basic I/O object, it provides socket and pipe //! communication as well as file access. It does not buffer reads and
94a9052014-09-23Henrik Grubbström (Grubba) //! writes by default, and provides no line-by-line reading, that is done //! with @[Stdio.FILE] object.
3bc55b2003-10-29Martin Stjernholm //! //! @note //! The file or stream will normally be closed when this object is //! destructed (unless there are more objects that refer to the same //! file through use of @[assign] or @[dup]). Objects do not contain //! cyclic references in themselves, so they will be destructed timely //! when they run out of references. //! //! @seealso //! @[Stdio.FILE]
c46feb1998-04-05Fredrik Hübinette (Hubbe) class File {
cb1d132009-02-22Henrik Grubbström (Grubba)  optional inherit Fd;
f6b99f2009-02-24Henrik Grubbström (Grubba) 
5667792014-10-04Henrik Grubbström (Grubba)  // This is needed in case we get overloaded by strange code // (socktest.pike). protected Fd fd_factory() { return File()->_fd; } protected Stdio.Buffer inbuffer, outbuffer;
cb65012014-10-01Martin Nilsson  //! Toggle the file to Buffer mode.
8923ca2014-09-03Per Hedbor  //!
cb65012014-10-01Martin Nilsson  //! In this mode reading and writing will be done via Buffer
6f8aab2014-09-03Per Hedbor  //! objects, in the directions you included buffers.
8923ca2014-09-03Per Hedbor  //!
94a9052014-09-23Henrik Grubbström (Grubba)  //! @param in
7f44b82016-05-25Henrik Grubbström (Grubba)  //! Input buffer. If this buffer is non-empty, its contents //! will be returned after any already received data.
94a9052014-09-23Henrik Grubbström (Grubba)  //! //! @param out
7f44b82016-05-25Henrik Grubbström (Grubba)  //! Output buffer. If this buffer is non-empty, its contents //! will be sent after any data already queued for sending.
8923ca2014-09-03Per Hedbor  //! //! @note //! Normally you call @[write] to re-trigger the write callback if //! you do not output anything in it (which will stop it from //! re-occuring again). //!
6f8aab2014-09-03Per Hedbor  //! This will work with buffered output mode as well, but simply //! adding more data to the output buffer will work as well.
5667792014-10-04Henrik Grubbström (Grubba)  //! //! @seealso
2631cd2017-06-29Martin Nilsson  //! @[query_buffer_mode()]
cb65012014-10-01Martin Nilsson  void set_buffer_mode( Stdio.Buffer|int(0..0) in,Stdio.Buffer|int(0..0) out )
8923ca2014-09-03Per Hedbor  {
409c4d2016-05-28Henrik Grubbström (Grubba)  if (in && inbuffer && sizeof(inbuffer)) {
7f44b82016-05-25Henrik Grubbström (Grubba)  // Behave as if any data in the new buffer was appended // to the old input buffer. in->add(inbuffer->read(), in->read()); }
8923ca2014-09-03Per Hedbor  inbuffer = in;
7f44b82016-05-25Henrik Grubbström (Grubba)  if (outbuffer) {
d8a1522014-10-04Henrik Grubbström (Grubba)  outbuffer->__fd_set_output( 0 );
7f44b82016-05-25Henrik Grubbström (Grubba)  if (out && sizeof(outbuffer)) { // Behave as if any data in the new output buffer was // appended to the old output buffer. out->add(outbuffer->read(), out->read()); } }
d9ada12014-09-04Per Hedbor  if( outbuffer = out )
ed50872015-02-28Arne Goedeke  outbuffer->__fd_set_output( ::write );
8923ca2014-09-03Per Hedbor  }
5667792014-10-04Henrik Grubbström (Grubba)  //! Get the active input and output buffers that have been //! set with @[set_buffer_mode()] (if any). //! //! @returns //! Returns an array with two elements: //! @array
af99b72014-10-16Henrik Grubbström (Grubba)  //! @elem Stdio.Buffer 0
5667792014-10-04Henrik Grubbström (Grubba)  //! The current input buffer.
af99b72014-10-16Henrik Grubbström (Grubba)  //! @elem Stdio.Buffer 1
5667792014-10-04Henrik Grubbström (Grubba)  //! The current output buffer. //! @endarray //! //! @seealso //! @[set_buffer_mode()] array(Stdio.Buffer|int(0..0)) query_buffer_mode()
f6b99f2009-02-24Henrik Grubbström (Grubba)  {
5667792014-10-04Henrik Grubbström (Grubba)  return ({ inbuffer, outbuffer });
f6b99f2009-02-24Henrik Grubbström (Grubba)  }
ad66752014-05-26Martin Nilsson 
ba6d7b2001-04-19Martin Stjernholm #ifdef TRACK_OPEN_FILES
ff17962014-08-15Martin Nilsson  /*protected*/ int open_file_id = next_open_file_id++;
ba6d7b2001-04-19Martin Stjernholm #endif
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
30204c2014-10-04Henrik Grubbström (Grubba)  // FIXME: Is this variable used for anything?
dfd8262000-11-06Per Hedbor  int is_file;
30204c2014-10-04Henrik Grubbström (Grubba)  protected read_callback_t ___read_callback; protected write_callback_t ___write_callback; protected function(mixed|void:int) ___close_callback; protected function(mixed|void,string|void:int) ___read_oob_callback; protected function(mixed|void:int) ___write_oob_callback; protected function(mixed|void,int:int) ___fs_event_callback; protected mixed ___id;
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG
30204c2014-10-04Henrik Grubbström (Grubba)  protected string __closed_backtrace; #define CHECK_OPEN() do { \ if(!is_open()) \ { \ error( "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" ) ); \ } \ } while(0)
41a8b01998-09-01Fredrik Hübinette (Hubbe) #else #define CHECK_OPEN()
35dd981998-07-18Fredrik Hübinette (Hubbe) #endif
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Returns the error code for the last command on this file. //! Error code is normally cleared when a command is successful. //!
2f55e91998-05-27Fredrik Hübinette (Hubbe)  int errno() {
ef3ada2004-04-05Martin Stjernholm  return ::errno();
2f55e91998-05-27Fredrik Hübinette (Hubbe)  }
9eaf1d2008-06-28Martin Nilsson  protected string|int debug_file; protected string debug_mode; protected int debug_bits;
5a2a2c2000-09-10Per Hedbor 
8824d92000-09-10Henrik Grubbström (Grubba)  optional void _setup_debug( string f, string m, int|void b )
5a2a2c2000-09-10Per Hedbor  { debug_file = f; debug_mode = m; debug_bits = b; }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf( int type, mapping flags )
5a2a2c2000-09-10Per Hedbor  {
ce3fd32002-11-29Martin Nilsson  if(type!='O') return 0; return sprintf("%O(%O, %O, %o /* fd=%d */)", this_program, debug_file, debug_mode, debug_bits||0777,
9ba5f02004-04-06Martin Stjernholm  _fd && is_open() ? query_fd() : -1 );
5a2a2c2000-09-10Per Hedbor  }
8923ca2014-09-03Per Hedbor  // @decl int open(int fd, string mode)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl int open(string filename, string mode) //! @decl int open(string filename, string mode, int mask) //! //! Open a file for read, write or append. The parameter @[mode] should //! contain one or more of the following letters: //! @string
cbe8c92003-04-07Martin Nilsson  //! @value "r"
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Open file for reading.
cbe8c92003-04-07Martin Nilsson  //! @value "w"
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Open file for writing.
cbe8c92003-04-07Martin Nilsson  //! @value "a" //! Open file for append (use with @expr{"w"@}). //! @value "t" //! Truncate file at open (use with @expr{"w"@}). //! @value "c" //! Create file if it doesn't exist (use with @expr{"w"@}). //! @value "x" //! Fail if file already exists (use with @expr{"c"@}).
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @endstring //!
cbe8c92003-04-07Martin Nilsson  //! @[mode] should always contain at least one of the letters //! @expr{"r"@} or @expr{"w"@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
cbe8c92003-04-07Martin Nilsson  //! The parameter @[mask] is protection bits to use if the file is //! created. Default is @expr{0666@} (read+write for all in octal //! notation).
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @returns
cbe8c92003-04-07Martin Nilsson  //! This function returns @expr{1@} for success, @expr{0@} otherwise.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso //! @[close()], @[create()] //!
217a001998-04-14Fredrik Hübinette (Hubbe)  int open(string file, string mode, void|int bits)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
dfd8262000-11-06Per Hedbor  is_file = 1;
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
65340d2014-08-15Martin Nilsson  if (undefinedp(bits)) bits=0666;
5a2a2c2000-09-10Per Hedbor  debug_file = file; debug_mode = mode; debug_bits = bits;
ef3ada2004-04-05Martin Stjernholm  if (::open(file,mode,bits)) { register_open_file (file, open_file_id, backtrace()); fix_internal_callbacks(); return 1; } return 0;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
59db4f2013-06-11Martin Nilsson #if constant(_Stdio.__HAVE_OPENPT__)
0e49202003-05-15Marcus Comstedt  //! @decl int openpt(string mode) //! //! Open the master end of a pseudo-terminal pair. The parameter //! @[mode] should contain one or more of the following letters: //! @string //! @value "r" //! Open terminal for reading. //! @value "w" //! Open terminal for writing. //! @endstring //! //! @[mode] should always contain at least one of the letters //! @expr{"r"@} or @expr{"w"@}. //! //! @seealso //! @[grantpt()] //! int openpt(string mode) { is_file = 0; #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif debug_file = "pty master"; debug_mode = mode; debug_bits=0;
ef3ada2004-04-05Martin Stjernholm  if (::openpt(mode)) { register_open_file ("pty master", open_file_id, backtrace()); fix_internal_callbacks(); return 1; } return 0;
0e49202003-05-15Marcus Comstedt  } #endif
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This makes this file into a socket ready for connections. The reason //! for this function is so that you can set the socket to nonblocking //! or blocking (default is blocking) before you call @[connect()]. //!
914cec2008-12-12Jonas Wallden  //! @param port //! If you give a port number to this function, the socket will be //! bound to this port locally before connecting anywhere. This is //! only useful for some silly protocols like @b{FTP@}. The port can //! also be specified as a string, giving the name of the service
26bf982013-10-22Chris Angelico  //! associated with the port. Pass -1 to not specify a port (eg to //! bind only to an address).
914cec2008-12-12Jonas Wallden  //! //! @param address //! You may specify an address to bind to if your machine has many IP //! numbers. //!
0e77e92008-12-14Marcus Comstedt  //! @param family_hint
914cec2008-12-12Jonas Wallden  //! A protocol family for the socket can be specified. If no family is //! specified, one which is appropriate for the address is automatically
0e77e92008-12-14Marcus Comstedt  //! selected. Thus, there is normally no need to specify it. If you //! do not want to specify a bind address, you can provide the address //! as a hint here instead, to allow the automatic selection to work //! anyway.
242ac52003-04-26Marcus Comstedt  //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @returns //! This function returns 1 for success, 0 otherwise. //! //! @seealso //! @[connect()], @[set_nonblocking()], @[set_blocking()] //!
0e77e92008-12-14Marcus Comstedt  int open_socket(int|string|void port, string|void address, int|string|void family_hint)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
dfd8262000-11-06Per Hedbor  is_file = 0;
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
5a2a2c2000-09-10Per Hedbor  debug_file="socket"; debug_mode=0; debug_bits=0;
ef3ada2004-04-05Martin Stjernholm  int ok;
0ec14c1998-04-06Henrik Grubbström (Grubba)  switch(query_num_arg()) { case 0:
ef3ada2004-04-05Martin Stjernholm  ok = ::open_socket(); break;
0ec14c1998-04-06Henrik Grubbström (Grubba)  case 1:
ef3ada2004-04-05Martin Stjernholm  ok = ::open_socket(port); break;
242ac52003-04-26Marcus Comstedt  case 2:
ef3ada2004-04-05Martin Stjernholm  ok = ::open_socket(port, address); break;
242ac52003-04-26Marcus Comstedt  default:
0e77e92008-12-14Marcus Comstedt  ok = ::open_socket(port, address, family_hint);
ef3ada2004-04-05Martin Stjernholm  break; } if (ok) { register_open_file ("socket", open_file_id, backtrace()); fix_internal_callbacks();
0ec14c1998-04-06Henrik Grubbström (Grubba)  }
ef3ada2004-04-05Martin Stjernholm  return ok;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
86eae42014-08-26Per Hedbor  //! Open a TCP/IP connection to the specified destination. //! //! In nonblocking mode, success is indicated with the write-callback, //! and failure with the close-callback or the read_oob-callback. //! //! The @[host] argument is the hostname or IP number of the remote //! machine. //! //! A local IP and port can be explicitly bound by specifying //! @[client] and @[client_port]. //! //! If the @[data] argument is included the socket will use //! TCP_FAST_OPEN if posible. In this mode the the function will //! return the part of the data that has not been sent to the remote //! server yet instead of 1 (you will have to use @[write] to send //! this data). //! //! Note that TCP_FAST_OPEN requires server support, the connection //! might fail even though the remote server exists. It might be
7a41bf2017-02-19Chris Angelico  //! advisable to retry without TCP_FAST_OPEN (and remember this
86eae42014-08-26Per Hedbor  //! fact)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @returns
86eae42014-08-26Per Hedbor  //! This function returns 1 or the remaining @[data] for success, 0 //! otherwise.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @note
86eae42014-08-26Per Hedbor  //!
cbe8c92003-04-07Martin Nilsson  //! In nonblocking mode @expr{0@} (zero) may be returned and
86eae42014-08-26Per Hedbor  //! @[errno()] set to @expr{EWOULDBLOCK@} or @expr{WSAEWOULDBLOCK@}. //! //! This should not be regarded as a
cbe8c92003-04-07Martin Nilsson  //! connection failure. In nonblocking mode you need to wait for a //! write or close callback before you know if the connection failed //! or not.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso
3bedfb2002-05-19Per Hedbor  //! @[query_address()], @[async_connect()], @[connect_unix()]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
86eae42014-08-26Per Hedbor  variant int connect(string host, int(0..)|string port) { #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif is_file = 0; debug_file = "socket"; debug_mode = host+":"+port; debug_bits = 0; if(::connect(host, port)) { register_open_file ("socket", open_file_id, backtrace()); fix_internal_callbacks(); return 1; } return 0; } variant int connect(string host, int(0..)|string port, string client, int(0..)|string client_port)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
dfd8262000-11-06Per Hedbor  is_file = 0;
9774a32000-12-12Henrik Grubbström (Grubba)  debug_file = "socket";
3524712015-05-26Martin Nilsson  debug_mode = host+":"+port;
9774a32000-12-12Henrik Grubbström (Grubba)  debug_bits = 0;
86eae42014-08-26Per Hedbor  if (::connect(host, port, client, client_port)) { register_open_file ("socket", open_file_id, backtrace()); fix_internal_callbacks(); return 1; } return 0; }
1649e22014-08-26Per Hedbor  variant string connect(string host, int(0..)|string port, string data) {
525a662014-08-26Per Hedbor  return connect(host,port,0,0,data);
1649e22014-08-26Per Hedbor  }
86eae42014-08-26Per Hedbor  variant string connect(string host, int(0..)|string port, int(0..0)|string client, int(0..)|string client_port, string data) { #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif is_file = 0; debug_file = "socket"; debug_mode = host+":"+port; debug_bits = 0; if( (data = ::connect(host, port, client, client_port, data)) ) { register_open_file ("socket", open_file_id, backtrace()); fix_internal_callbacks(); return data;
ef3ada2004-04-05Martin Stjernholm  } return 0;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
59db4f2013-06-11Martin Nilsson #if constant(_Stdio.__HAVE_CONNECT_UNIX__)
3bedfb2002-05-19Per Hedbor  int connect_unix(string path) //! Open a UNIX domain socket connection to the specified destination.
3524712015-05-26Martin Nilsson  //!
3bedfb2002-05-19Per Hedbor  //! @returns
cbe8c92003-04-07Martin Nilsson  //! Returns @expr{1@} on success, and @expr{0@} on failure.
3bedfb2002-05-19Per Hedbor  //! //! @note //! Nonblocking mode is not supported while connecting { #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif is_file = 0; debug_file = "unix_socket"; debug_mode = path; debug_bits = 0;
ef3ada2004-04-05Martin Stjernholm  if (::connect_unix( path )) { register_open_file ("unix_socket", open_file_id, backtrace()); fix_internal_callbacks(); return 1; } return 0;
3bedfb2002-05-19Per Hedbor  }
c7ab012002-11-28Marcus Comstedt #endif
3bedfb2002-05-19Per Hedbor 
9aee552009-04-25Martin Stjernholm  private function(int, mixed ...:void) _async_cb; private array(mixed) _async_args; private void _async_check_cb(mixed|void ignored)
d65ca91999-01-30Henrik Grubbström (Grubba)  { // Copy the args to avoid races. function(int, mixed ...:void) cb = _async_cb; array(mixed) args = _async_args; _async_cb = 0; _async_args = 0;
11f3ce2009-04-25Martin Stjernholm  set_callbacks (0,0,0,0,0);
b37f042001-11-22Henrik Grubbström (Grubba)  if (cb) {
ef3ada2004-04-05Martin Stjernholm  if (is_open() && query_address()) {
b37f042001-11-22Henrik Grubbström (Grubba)  // Connection OK. cb(1, @args); } else { // Connection failed. // Make sure the state is reset. close(); cb(0, @args); } }
d65ca91999-01-30Henrik Grubbström (Grubba)  }
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
7db3642014-09-29Henrik Grubbström (Grubba)  //! Read (optionally buffered) data from a file or a stream. //! //! Proxy function for @[Fd::read()], that adds support for //! the buffering configured by @[set_buffer_mode()] //! //! @seealso //! @[read_function()], @[write()], @[Fd::read()] string(8bit) read(int|void nbytes, int(0..1)|void not_all) { if (inbuffer) { if (!nbytes) return ""; if (!sizeof(inbuffer) || (!not_all && sizeof(inbuffer) < nbytes)) { // Try filling the buffer with the remaining wanted bytes. if ((inbuffer->input_from(this, nbytes - sizeof(inbuffer)) < 0) && !sizeof(inbuffer)) { // Read error and no data in the buffer. // Propagate errno. _errno = predef::errno(); return 0; } } return inbuffer->try_read(nbytes); } return ::read(nbytes, not_all); }
49bbfd2001-06-16Per Hedbor  function(:string) read_function(int nbytes) //! Returns a function that when called will call @[read] with //! nbytes as argument. Can be used to get various callback
0faed92003-07-22Henrik Grubbström (Grubba)  //! functions, eg for the fourth argument to //! @[String.SplitIterator].
49bbfd2001-06-16Per Hedbor  {
d9ada12014-09-04Per Hedbor  return lambda() { return read(nbytes); };
49bbfd2001-06-16Per Hedbor  }
297a932003-04-18Martin Stjernholm  String.SplitIterator|LineIterator line_iterator( int|void trim )
3524712015-05-26Martin Nilsson  //! Returns an iterator that will loop over the lines in this file.
0faed92003-07-22Henrik Grubbström (Grubba)  //! If trim is true, all @tt{'\r'@} characters will be removed from //! the input.
49bbfd2001-06-16Per Hedbor  { if( trim )
809a322009-12-03Martin Stjernholm  return String.SplitIterator( "",(<'\n','\r'>),1, read_function(DATA_CHUNK_SIZE));
ba47542001-06-16Per Hedbor  // This one is about twice as fast, but it's way less flexible.
809a322009-12-03Martin Stjernholm  return LineIterator( read_function(DATA_CHUNK_SIZE) );
49bbfd2001-06-16Per Hedbor  }
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
76f8972002-03-12Henrik Grubbström (Grubba)  //! Open a TCP/IP connection asynchronously. //! //! This function is similar to @[connect()], but works asynchronously. //! //! @param host //! Hostname or IP to connect to. //! //! @param port
3c0d582003-04-22Marcus Comstedt  //! Port number or service name to connect to.
76f8972002-03-12Henrik Grubbström (Grubba)  //! //! @param callback //! Function to be called on completion.
cbe8c92003-04-07Martin Nilsson  //! The first argument will be @expr{1@} if a connection was
d947872009-04-25Martin Stjernholm  //! successfully established, and @expr{0@} (zero) on failure.
76f8972002-03-12Henrik Grubbström (Grubba)  //! The rest of the arguments to @[callback] are passed //! verbatim from @[args]. //! //! @param args //! Extra arguments to pass to @[callback]. //! //! @returns
a16ebd2016-11-17Martin Nilsson  //! Returns @expr{0@} on failure to open a socket, and @expr{1@} //! if @[callback] will be used.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @note
76f8972002-03-12Henrik Grubbström (Grubba)  //! The socket may be opened with @[open_socket()] ahead of //! the call to this function, but it is not required. //!
3bc55b2003-10-29Martin Stjernholm  //! @note //! This object is put in callback mode by this function. For //! @[callback] to be called, the backend must be active. See e.g. //! @[set_read_callback] for more details about backends and //! callback mode.
76f8972002-03-12Henrik Grubbström (Grubba)  //!
3bc55b2003-10-29Martin Stjernholm  //! @note //! The socket will be in nonblocking state if the connection is //! successful, and any callbacks will be cleared.
76f8972002-03-12Henrik Grubbström (Grubba)  //! //! @seealso //! @[connect()], @[open_socket()], @[set_nonblocking()]
3c0d582003-04-22Marcus Comstedt  int async_connect(string host, int|string port,
d65ca91999-01-30Henrik Grubbström (Grubba)  function(int, mixed ...:void) callback, mixed ... args) {
ef3ada2004-04-05Martin Stjernholm  if (!is_open() || !::stat()->issock ||
76f8972002-03-12Henrik Grubbström (Grubba)  catch { throw(query_address()); }) { // Open a new socket if: // o We don't have an fd. // o The fd isn't a socket. // o query_address() returns non zero (ie connected). // o query_address() throws an error (eg delayed UDP error) [bug 2691].
914cec2008-12-12Jonas Wallden  //
76f8972002-03-12Henrik Grubbström (Grubba)  // This code is here to support the socket being opened (and locally // bound) by the calling code, to support eg FTP.
0e77e92008-12-14Marcus Comstedt  if (!open_socket(-1, 0, host)) {
76f8972002-03-12Henrik Grubbström (Grubba)  // Out of sockets? return 0; }
d65ca91999-01-30Henrik Grubbström (Grubba)  }
9944f82002-02-14Martin Nilsson 
d65ca91999-01-30Henrik Grubbström (Grubba)  _async_cb = callback; _async_args = args;
b37f042001-11-22Henrik Grubbström (Grubba)  set_nonblocking(0, _async_check_cb, _async_check_cb, _async_check_cb, 0);
d65ca91999-01-30Henrik Grubbström (Grubba)  mixed err;
c2e0611999-04-01Henrik Grubbström (Grubba)  int res; if (err = catch(res = connect(host, port))) {
d65ca91999-01-30Henrik Grubbström (Grubba)  // Illegal format. -- Bad hostname?
11f3ce2009-04-25Martin Stjernholm  set_callbacks (0, 0, 0, 0, 0);
b37f042001-11-22Henrik Grubbström (Grubba)  call_out(_async_check_cb, 0);
c2e0611999-04-01Henrik Grubbström (Grubba)  } else if (!res) { // Connect failed.
11f3ce2009-04-25Martin Stjernholm  set_callbacks (0, 0, 0, 0, 0);
b37f042001-11-22Henrik Grubbström (Grubba)  call_out(_async_check_cb, 0);
d65ca91999-01-30Henrik Grubbström (Grubba)  }
18096f2003-08-22Martin Nilsson  return 1; // OK so far. (Or rather the callback will be used).
d65ca91999-01-30Henrik Grubbström (Grubba)  }
7e28492003-10-05Henrik Grubbström (Grubba)  //! This function creates a pipe between the object it was called in //! and an object that is returned. //!
20ce762003-10-08Martin Nilsson  //! @param required_properties
7e28492003-10-05Henrik Grubbström (Grubba)  //! Binary or (@[predef::`|()]) of required @expr{PROP_@} properties. //! @int //! @value PROP_IPC //! The resulting pipe may be used for inter process communication. //! @value PROP_NONBLOCK //! The resulting pipe supports nonblocking I/O. //! @value PROP_SHUTDOWN //! The resulting pipe supports shutting down transmission in either //! direction (see @[close()]). //! @value PROP_BUFFERED //! The resulting pipe is buffered (usually 4KB). //! @value PROP_BIDIRECTIONAL //! The resulting pipe is bi-directional.
89fdb32010-11-19Henrik Grubbström (Grubba)  //! @value PROP_SEND_FD
f126b62010-11-19Henrik Grubbström (Grubba)  //! The resulting pipe might support sending of file descriptors //! (see @[send_fd()] and @[receive_fd()] for details).
7e28492003-10-05Henrik Grubbström (Grubba)  //! @value PROP_REVERSE //! The resulting pipe supports communication "backwards" (but //! not necessarily "forwards", see @[PROP_BIDIRECTIONAL]). //! @endint //! The default is @expr{PROP_NONBLOCK|PROP_BIDIRECTIONAL@}. //! //! If @[PROP_BIDIRECTIONAL] isn't specified, the read-end is this //! object, and the write-end is the returned object (unless //! @[PROP_REVERSE] has been specified, in which case it is the other //! way around). //! //! The two ends of a bi-directional pipe are indistinguishable. //! //! If the File object this function is called in was open to begin with, //! it will be closed before the pipe is created.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
7e28492003-10-05Henrik Grubbström (Grubba)  //! @note //! Calling this function with an argument of @tt{0@} is not the //! same as calling it with no arguments.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso
f126b62010-11-19Henrik Grubbström (Grubba)  //! @[Process.create_process()], @[send_fd()], @[receive_fd()],
89fdb32010-11-19Henrik Grubbström (Grubba)  //! @[PROP_IPC], @[PROP_NONBLOCK], @[PROP_SEND_FD],
7e28492003-10-05Henrik Grubbström (Grubba)  //! @[PROP_SHUTDOWN], @[PROP_BUFFERED], @[PROP_REVERSE], //! @[PROP_BIDIRECTIONAL]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
7e28492003-10-05Henrik Grubbström (Grubba)  File pipe(void|int required_properties)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif
dfd8262000-11-06Per Hedbor  is_file = 0;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  if(query_num_arg()==0)
7e28492003-10-05Henrik Grubbström (Grubba)  required_properties=PROP_NONBLOCK | PROP_BIDIRECTIONAL;
f6b99f2009-02-24Henrik Grubbström (Grubba)  if(Fd fd = ::pipe(required_properties))
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
f6b99f2009-02-24Henrik Grubbström (Grubba)  File o = function_object(fd->read);
5a2a2c2000-09-10Per Hedbor  o->_setup_debug( "pipe", 0 );
ef3ada2004-04-05Martin Stjernholm  register_open_file ("pipe", open_file_id, backtrace()); register_open_file ("pipe", o->open_file_id, backtrace()); fix_internal_callbacks();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  return o; }
ad66752014-05-26Martin Nilsson  return 0;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
59db4f2013-06-11Martin Nilsson #if constant(_Stdio.__HAVE_OPENAT__)
94fb5d2008-03-07Henrik Grubbström (Grubba)  //! @decl File openat(string filename, string mode) //! @decl File openat(string filename, string mode, int mask) //! //! Open a file relative to an open directory. //! //! @seealso //! @[File.statat()], @[File.unlinkat()] File openat(string filename, string mode, int|void mask) { if(query_num_arg()<3) mask = 0777;
f6b99f2009-02-24Henrik Grubbström (Grubba)  if(Fd fd = ::openat(filename, mode, mask))
94fb5d2008-03-07Henrik Grubbström (Grubba)  {
f6b99f2009-02-24Henrik Grubbström (Grubba)  File o = function_object(fd->read);
94fb5d2008-03-07Henrik Grubbström (Grubba)  string path = combine_path(debug_file||"", filename); o->_setup_debug(path, mode, mask); register_open_file(path, o->open_file_id, backtrace()); return o; }
ad66752014-05-26Martin Nilsson  return 0;
94fb5d2008-03-07Henrik Grubbström (Grubba)  }
550f192008-03-07Henrik Grubbström (Grubba) #endif
94fb5d2008-03-07Henrik Grubbström (Grubba) 
59db4f2013-06-11Martin Nilsson #if constant(_Stdio.__HAVE_SEND_FD__)
f126b62010-11-19Henrik Grubbström (Grubba)  //!
0c91d22013-06-17Martin Nilsson  void send_fd(File|Fd file)
f126b62010-11-19Henrik Grubbström (Grubba)  {
0c91d22013-06-17Martin Nilsson  ::send_fd(file->_fd);
f126b62010-11-19Henrik Grubbström (Grubba)  } #endif
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl void create() //! @decl void create(string filename) //! @decl void create(string filename, string mode) //! @decl void create(string filename, string mode, int mask) //! @decl void create(string descriptorname) //! @decl void create(int fd) //! @decl void create(int fd, string mode) //! //! There are four basic ways to create a Stdio.File object.
a9ecdf2002-06-23Martin Nilsson  //! The first is calling it without any arguments, in which case the you'd
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! have to call @[open()], @[connect()] or some other method which connects //! the File object with a stream. //! //! The second way is calling it with a @[filename] and open @[mode]. This is //! the same thing as cloning and then calling @[open()], except shorter and //! faster. //!
cbe8c92003-04-07Martin Nilsson  //! The third way is to call it with @[descriptorname] of @expr{"stdin"@}, //! @expr{"stdout"@} or @expr{"stderr"@}. This will open the specified
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! standard stream. //! //! For the advanced users, you can use the file descriptors of the //! systems (note: emulated by pike on some systems - like NT). This is //! only useful for streaming purposes on unix systems. This is @b{not //! recommended at all@} if you don't know what you're into. Default
cbe8c92003-04-07Martin Nilsson  //! @[mode] for this is @expr{"rw"@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @note //! Open mode will be filtered through the system UMASK. You //! might need to use @[chmod()] later. //! //! @seealso //! @[open()], @[connect()], @[Stdio.FILE],
9eaf1d2008-06-28Martin Nilsson  protected void create(int|string|void file,void|string mode,void|int bits)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
65340d2014-08-15Martin Nilsson  if (undefinedp(file))
ef3ada2004-04-05Martin Stjernholm  return;
3524712015-05-26Martin Nilsson  debug_file = file;
5a2a2c2000-09-10Per Hedbor  debug_mode = mode; debug_bits = bits;
217a001998-04-14Fredrik Hübinette (Hubbe)  switch(file)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
217a001998-04-14Fredrik Hübinette (Hubbe)  case "stdin":
cb1d132009-02-22Henrik Grubbström (Grubba)  create(0, mode, bits);
ad66752014-05-26Martin Nilsson  break;
70333c1999-10-01Fredrik Hübinette (Hubbe) 
217a001998-04-14Fredrik Hübinette (Hubbe)  case "stdout":
cb1d132009-02-22Henrik Grubbström (Grubba)  create(1, mode, bits);
217a001998-04-14Fredrik Hübinette (Hubbe)  break;
3524712015-05-26Martin Nilsson 
217a001998-04-14Fredrik Hübinette (Hubbe)  case "stderr":
cb1d132009-02-22Henrik Grubbström (Grubba)  create(2, mode, bits);
217a001998-04-14Fredrik Hübinette (Hubbe)  break;
478e4a1999-09-29Mirar (Pontus Hagland)  case 0..0x7fffffff:
ad66752014-05-26Martin Nilsson  if (!mode) mode="rw";
cb1d132009-02-22Henrik Grubbström (Grubba)  ::create(file, mode);
ba6d7b2001-04-19Martin Stjernholm  register_open_file ("fd " + file, open_file_id, backtrace());
478e4a1999-09-29Mirar (Pontus Hagland) #ifdef __STDIO_DEBUG __closed_backtrace=0; #endif break;
217a001998-04-14Fredrik Hübinette (Hubbe)  default:
dfd8262000-11-06Per Hedbor  is_file = 1;
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;
478e4a1999-09-29Mirar (Pontus Hagland)  if(!mode) mode="r"; if (!::open(file,mode,bits))
8490d22016-11-05Martin Nilsson  error("Failed to open %O mode %O : %s.\n", file, mode, strerror(errno()));
ef3ada2004-04-05Martin Stjernholm  register_open_file (file, open_file_id, backtrace());
ad66752014-05-26Martin Nilsson  break;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  } }
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function takes a clone of Stdio.File and assigns all //! variables of this file from it. It can be used together with @[dup()] //! to move files around. //! //! @seealso //! @[dup()] //!
5a2a2c2000-09-10Per Hedbor  int assign(File|Fd o)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
5abe942004-04-07Henrik Grubbström (Grubba)  BE_WERR("assign()\n");
dfd8262000-11-06Per Hedbor  is_file = o->is_file;
f6b99f2009-02-24Henrik Grubbström (Grubba)  o->dup2(_fd);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  return 0; }
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function returns a clone of Stdio.File with all variables //! copied from this file. //! //! @note //! All variables, even @tt{id@}, are copied. //! //! @seealso //! @[assign()]
5a2a2c2000-09-10Per Hedbor  File dup()
c158fe1998-04-10Henrik Grubbström (Grubba)  {
5abe942004-04-07Henrik Grubbström (Grubba)  BE_WERR("dup()\n");
f6b99f2009-02-24Henrik Grubbström (Grubba)  return function_object(::dup()->read);
c158fe1998-04-10Henrik Grubbström (Grubba)  }
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl int close()
df4a9d2001-11-22Martin Nilsson  //! @decl int close(string direction)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! Close the file. Optionally, specify "r", "w" or "rw" to close just
df4a9d2001-11-22Martin Nilsson  //! the read, just the write or both read and write directions of the file
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! respectively. //!
5372e12003-10-22Martin Stjernholm  //! An exception is thrown if an I/O error occurs. //! //! @returns //! Nonzero is returned if the file wasn't open in the specified //! direction, zero otherwise. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @note //! This function will not call the @tt{close_callback@}. //! //! @seealso
df4a9d2001-11-22Martin Nilsson  //! @[open], @[open_socket]
bbaf2b2000-12-12Henrik 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)  {
ef3ada2004-04-05Martin Stjernholm  // Avoid cyclic refs. #define FREE_CB(X) _fd->_##X = 0
fbbc091999-05-13Fredrik Hübinette (Hubbe)  FREE_CB(read_callback); FREE_CB(write_callback); FREE_CB(read_oob_callback); FREE_CB(write_oob_callback);
ef3ada2004-04-05Martin Stjernholm 
ba6d7b2001-04-19Martin Stjernholm  register_close_file (open_file_id);
35dd981998-07-18Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG __closed_backtrace=master()->describe_backtrace(backtrace()); #endif
5372e12003-10-22Martin Stjernholm  return 1;
35dd981998-07-18Fredrik Hübinette (Hubbe)  }
5372e12003-10-22Martin Stjernholm  return 0;
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
ca54c82005-01-31Martin Stjernholm #ifdef STDIO_CALLBACK_TEST_MODE
49939e2009-02-15Henrik Grubbström (Grubba)  // Test mode where we are nasty and never return a string longer
ca54c82005-01-31Martin Stjernholm  // than one byte in the read callbacks and never let nonblocking // writes write more than one byte. Useful to test that the callback // stuff really handles packets cut at odd positions.
a08b262014-10-03Henrik Grubbström (Grubba)  int write (sprintf_format|array(string) s, sprintf_args... args)
ca54c82005-01-31Martin Stjernholm  {
a08b262014-10-03Henrik Grubbström (Grubba)  if (!(::mode() & PROP_IS_NONBLOCKING)) { if (outbuffer && sizeof(outbuffer)) { outbuffer->__fd_set_output(0);
0f9a9a2015-03-21Henrik Grubbström (Grubba)  int actual_bytes = outbuffer->output_to(::write);
a08b262014-10-03Henrik Grubbström (Grubba) 
0c75472014-10-05Henrik Grubbström (Grubba)  outbuffer->__fd_set_output(::write);
a08b262014-10-03Henrik Grubbström (Grubba)  if (actual_bytes <= 0) { if (actual_bytes) _errno = predef::errno(); return actual_bytes; } if (sizeof(outbuffer)) return 0; }
ca54c82005-01-31Martin Stjernholm  return ::write (s, @args);
a08b262014-10-03Henrik Grubbström (Grubba)  } if (outbuffer && sizeof(outbuffer)) { outbuffer->__fd_set_output(0); string byte = outbuffer->read(1); int actual_bytes = ::write(byte);
0c75472014-10-05Henrik Grubbström (Grubba)  outbuffer->__fd_set_output(::write);
a08b262014-10-03Henrik Grubbström (Grubba)  if (actual_bytes <= 0) { outbuffer->unread(sizeof(byte)); return actual_bytes; } if (sizeof(outbuffer)) return 0; }
ca54c82005-01-31Martin Stjernholm  if (arrayp (s)) s *= ""; if (sizeof (args)) s = sprintf (s, @args); return ::write (s[..0]); }
7373322005-01-31Martin Stjernholm  int write_oob (string s, mixed... args)
ca54c82005-01-31Martin Stjernholm  { if (!(::mode() & PROP_IS_NONBLOCKING)) return ::write_oob (s, @args); if (sizeof (args)) s = sprintf (s, @args); return ::write_oob (s[..0]); }
a08b262014-10-03Henrik Grubbström (Grubba)  #else /* !STDIO_CALLBACK_TEST_MODE */
49ce3b2018-02-13Arne Goedeke  int write(sprintf_format|array(string)|object data_or_format,
a08b262014-10-03Henrik Grubbström (Grubba)  sprintf_args ... args) { if (outbuffer) { outbuffer->__fd_set_output(0); if (sizeof(outbuffer)) { // The write buffer isn't empty, so try to empty it. */
0f9a9a2015-03-21Henrik Grubbström (Grubba)  int bytes = outbuffer->output_to( ::write );
a08b262014-10-03Henrik Grubbström (Grubba)  if (sizeof(outbuffer) && (bytes > 0)) { // Not all was written. Probably EWOULDBLOCK. // We propagate errno below. bytes = 0; } if (bytes <= 0) { if (bytes) { // EWOULDBLOCK or other error. _errno = predef::errno(); }
0c75472014-10-05Henrik Grubbström (Grubba)  outbuffer->__fd_set_output(::write);
a08b262014-10-03Henrik Grubbström (Grubba)  return 0; } } // NB: Invariant: outbuffer is empty here. if (sizeof(args)) { if (arrayp(data_or_format)) { data_or_format = data_or_format * ""; } outbuffer->sprintf(data_or_format, args); } else { outbuffer->add(data_or_format); } int bytes = sizeof(outbuffer);
0c75472014-10-05Henrik Grubbström (Grubba)  int actual_bytes = outbuffer->output_to( ::write );
a08b262014-10-03Henrik Grubbström (Grubba)  if (actual_bytes <= 0) { // Write failure. Unwrite the outbuffer. _errno = predef::errno(); outbuffer->clear(); return actual_bytes; }
0c75472014-10-05Henrik Grubbström (Grubba)  outbuffer->__fd_set_output(::write);
a08b262014-10-03Henrik Grubbström (Grubba)  return bytes; } return ::write(data_or_format, @args); } #endif /* !STDIO_CALLBACK_TEST_MODE */
ca54c82005-01-31Martin Stjernholm 
6428d22015-03-16Martin Nilsson  private int __read_callback_error() { #if constant(System.EWOULDBLOCK) if (errno() == System.EWOULDBLOCK) { // Necessary to reregister since the callback is disabled // until a successful read() has been done. ::set_read_callback(__stdio_read_callback); return 0; } #endif ::set_read_callback(0); if (___close_callback) { BE_WERR (" calling close callback"); return ___close_callback(___id||this); } }
4e1d571999-04-19Henrik Grubbström (Grubba)  // FIXME: No way to specify the maximum to read.
9eaf1d2008-06-28Martin Nilsson  protected int __stdio_read_callback()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
a8852e2004-04-06Henrik Grubbström (Grubba)  BE_WERR("__stdio_read_callback()");
65de1c2005-01-31Martin Stjernholm  if (!___read_callback) {
f2524c2007-08-06Henrik Grubbström (Grubba)  if (___close_callback) { return __stdio_close_callback(); }
65de1c2005-01-31Martin Stjernholm  return 0; }
3bc55b2003-10-29Martin Stjernholm  if (!errno()) {
7446602018-03-04Arne Goedeke  if( object buffer = inbuffer )
8923ca2014-09-03Per Hedbor  {
7446602018-03-04Arne Goedeke  buffer->allocate(DATA_CHUNK_SIZE); int bytes = ::read(buffer); if (bytes > 0) { return ___read_callback( ___id||this, buffer ); } else
8923ca2014-09-03Per Hedbor  {
6428d22015-03-16Martin Nilsson  return __read_callback_error();
8923ca2014-09-03Per Hedbor  } }
ca54c82005-01-31Martin Stjernholm  string s; #ifdef STDIO_CALLBACK_TEST_MODE s = ::read (1, 1); #else
809a322009-12-03Martin Stjernholm  s = ::read(DATA_CHUNK_SIZE,1);
ca54c82005-01-31Martin Stjernholm #endif
f3ec252005-01-26Martin Stjernholm  if (s) { if(sizeof(s))
3bc55b2003-10-29Martin Stjernholm  {
51f1ce2015-09-06Martin Nilsson  BE_WERR(" calling read callback with %O", s);
d9ada12014-09-04Per Hedbor  return ___read_callback(___id||this, s);
3bc55b2003-10-29Martin Stjernholm  }
7696d62005-01-27Martin Stjernholm  BE_WERR (" got eof");
f3ec252005-01-26Martin Stjernholm  }
6428d22015-03-16Martin Nilsson  else
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from read()", strerror(errno()));
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
7696d62005-01-27Martin Stjernholm  else
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from backend", strerror(errno()));
7696d62005-01-27Martin Stjernholm 
6428d22015-03-16Martin Nilsson  return __read_callback_error();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
ca6bd02012-05-01Bill Welliver  protected int __stdio_fs_event_callback(int event_mask) {
d9ada12014-09-04Per Hedbor  BE_WERR ("__stdio_fs_event_callback()");
ca6bd02012-05-01Bill Welliver  if (!___fs_event_callback) return 0; if(errno())
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from read()", strerror(errno()));
d9ada12014-09-04Per Hedbor  return ___fs_event_callback(___id||this, event_mask);
ca6bd02012-05-01Bill Welliver  }
9eaf1d2008-06-28Martin Nilsson  protected int __stdio_close_callback()
b37f042001-11-22Henrik Grubbström (Grubba)  {
f3ec252005-01-26Martin Stjernholm  BE_WERR ("__stdio_close_callback()");
12c9652003-07-10Henrik Grubbström (Grubba) #if 0 if (!(::mode() & PROP_IS_NONBLOCKING)) ::set_nonblocking(); #endif /* 0 */
65de1c2005-01-31Martin Stjernholm  if (!___close_callback) return 0;
e784c82006-05-31Henrik Grubbström (Grubba)  if (!errno()) {
b37f042001-11-22Henrik Grubbström (Grubba)  // There's data to read...
f3ec252005-01-26Martin Stjernholm  //
3bc55b2003-10-29Martin Stjernholm  // FIXME: This doesn't work well since the close callback might // very well be called sometime later, due to an error if // nothing else. What we really need is a special error callback // from the backend. /mast
f3ec252005-01-26Martin Stjernholm  BE_WERR (" WARNING: data to read - __stdio_close_callback deregistered");
b37f042001-11-22Henrik Grubbström (Grubba)  ::set_read_callback(0);
fd1d392005-01-18Martin Stjernholm  //___close_callback = 0;
b37f042001-11-22Henrik Grubbström (Grubba)  }
67e5962005-04-08Henrik Grubbström (Grubba)  else {
7696d62005-01-27Martin Stjernholm #ifdef BACKEND_DEBUG if (errno())
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from backend", strerror(errno()));
7696d62005-01-27Martin Stjernholm  else BE_WERR (" got eof"); #endif
3bc55b2003-10-29Martin Stjernholm  ::set_read_callback(0);
7696d62005-01-27Martin Stjernholm  BE_WERR (" calling close callback");
d9ada12014-09-04Per Hedbor  return ___close_callback(___id||this);
b37f042001-11-22Henrik Grubbström (Grubba)  }
f3ec252005-01-26Martin Stjernholm  return 0;
b37f042001-11-22Henrik Grubbström (Grubba)  }
9eaf1d2008-06-28Martin Nilsson  protected int __stdio_write_callback()
3bc55b2003-10-29Martin Stjernholm  {
a8852e2004-04-06Henrik Grubbström (Grubba)  BE_WERR("__stdio_write_callback()");
65de1c2005-01-31Martin Stjernholm 
f3ec252005-01-26Martin Stjernholm  if (!errno()) {
65de1c2005-01-31Martin Stjernholm  if (!___write_callback) return 0;
f3ec252005-01-26Martin Stjernholm  BE_WERR (" calling write callback");
8923ca2014-09-03Per Hedbor  if( outbuffer ) { int res; if( sizeof( outbuffer ) )
0f9a9a2015-03-21Henrik Grubbström (Grubba)  res = outbuffer->output_to( ::write );
8923ca2014-09-03Per Hedbor  else { outbuffer->__fd_set_output( 0 );
d9ada12014-09-04Per Hedbor  res = ___write_callback(___id||this,outbuffer);
35ae632015-03-16Martin Nilsson  if( !this ) return res;
8923ca2014-09-03Per Hedbor  if( sizeof( outbuffer ) )
0f9a9a2015-03-21Henrik Grubbström (Grubba)  outbuffer->output_to( ::write );
0c75472014-10-05Henrik Grubbström (Grubba)  outbuffer->__fd_set_output( ::write );
8923ca2014-09-03Per Hedbor  } return res; }
d9ada12014-09-04Per Hedbor  return ___write_callback(___id||this);
f3ec252005-01-26Martin Stjernholm  }
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from backend", strerror(errno()));
f3ec252005-01-26Martin Stjernholm  // Don't need to report the error to ___close_callback here - we // know it isn't installed. If it were, either // __stdio_read_callback or __stdio_close_callback would be // installed and would get the error first. return 0;
3bc55b2003-10-29Martin Stjernholm  }
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson  protected int __stdio_read_oob_callback()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
f3ec252005-01-26Martin Stjernholm  BE_WERR ("__stdio_read_oob_callback()");
7696d62005-01-27Martin Stjernholm 
ca54c82005-01-31Martin Stjernholm  string s;
49939e2009-02-15Henrik Grubbström (Grubba)  if (!___read_oob_callback) { // The out of band callback was probably removed after the backend // was started. Propagate the event to __stdio_read_callback().
65de1c2005-01-31Martin Stjernholm  s = "";
49939e2009-02-15Henrik Grubbström (Grubba)  } else {
ca54c82005-01-31Martin Stjernholm #ifdef STDIO_CALLBACK_TEST_MODE
65de1c2005-01-31Martin Stjernholm  s = ::read_oob (1, 1);
ca54c82005-01-31Martin Stjernholm #else
809a322009-12-03Martin Stjernholm  s = ::read_oob(DATA_CHUNK_SIZE,1);
ca54c82005-01-31Martin Stjernholm #endif
65de1c2005-01-31Martin Stjernholm  }
3abdbd2004-04-05Martin Stjernholm  if(s)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
f3ec252005-01-26Martin Stjernholm  if (sizeof(s)) {
51f1ce2015-09-06Martin Nilsson  BE_WERR (" calling read oob callback with %O", s);
d9ada12014-09-04Per Hedbor  return ___read_oob_callback(___id||this, s);
f3ec252005-01-26Martin Stjernholm  }
7696d62005-01-27Martin Stjernholm  // If the backend doesn't support separate read oob events then // we'll get here if there's normal data to read or a read eof, // and due to the way file_read_oob in file.c currently clears // both read events, it won't call __stdio_read_callback or // __stdio_close_callback afterwards. Therefore we need to try a // normal read here.
49939e2009-02-15Henrik Grubbström (Grubba)  BE_WERR (" no oob data - trying __stdio_read_callback"); return __stdio_read_callback();
7696d62005-01-27Martin Stjernholm  } else {
8490d22016-11-05Martin Nilsson  BE_WERR (" got error %s from read_oob()", strerror(errno()));
7696d62005-01-27Martin Stjernholm 
3abdbd2004-04-05Martin Stjernholm #if constant(System.EWOULDBLOCK) if (errno() == System.EWOULDBLOCK) { // Necessary to reregister since the callback is disabled // until a successful read() has been done. ::set_read_oob_callback(__stdio_read_oob_callback);
f3ec252005-01-26Martin Stjernholm  return 0;
3abdbd2004-04-05Martin Stjernholm  } #endif
f3ec252005-01-26Martin Stjernholm  // In case the read fails (it shouldn't, but anyway..).
bbc6b71998-10-22Henrik Grubbström (Grubba)  ::set_read_oob_callback(0); if (___close_callback) {
f3ec252005-01-26Martin Stjernholm  BE_WERR (" calling close callback");
d9ada12014-09-04Per Hedbor  return ___close_callback(___id||this);
bbc6b71998-10-22Henrik Grubbström (Grubba)  }
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
f3ec252005-01-26Martin Stjernholm  return 0; }
217a001998-04-14Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson  protected int __stdio_write_oob_callback()
f3ec252005-01-26Martin Stjernholm  { BE_WERR ("__stdio_write_oob_callback()");
65de1c2005-01-31Martin Stjernholm  if (!___write_oob_callback) return 0;
f3ec252005-01-26Martin Stjernholm  BE_WERR (" calling write oob callback");
d9ada12014-09-04Per Hedbor  return ___write_oob_callback(___id||this);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
8923ca2014-09-03Per Hedbor  //! @decl void set_read_callback(function(mixed,string:int) read_cb)
cb65012014-10-01Martin Nilsson  //! @decl void set_read_callback(function(mixed,Buffer:int) read_cb)
3bc55b2003-10-29Martin Stjernholm  //! @decl void set_write_callback(function(mixed:int) write_cb)
cb65012014-10-01Martin Nilsson  //! @decl void set_write_callback(function(mixed,Buffer:int) write_cb)
3bc55b2003-10-29Martin Stjernholm  //! @decl void set_read_oob_callback(function(mixed, string:int) read_oob_cb) //! @decl void set_write_oob_callback(function(mixed:int) write_oob_cb) //! @decl void set_close_callback(function(mixed:int) close_cb)
ca6bd02012-05-01Bill Welliver  //! @decl void set_fs_event_callback(function(mixed,int:int) fs_event_cb, int event_mask)
3bc55b2003-10-29Martin Stjernholm  //! //! These functions set the various callbacks, which will be called //! when various events occur on the stream. A zero as argument will
3abdbd2004-04-05Martin Stjernholm  //! remove the callback.
3bc55b2003-10-29Martin Stjernholm  //! //! A @[Pike.Backend] object is responsible for calling the //! callbacks. It requires a thread to be waiting in it to execute //! the calls. That means that only one of the callbacks will be //! running at a time, so you don't need mutexes between them. //! //! Unless you've specified otherwise with the @[set_backend] //! function, the default backend @[Pike.DefaultBackend] will be //! used. It's normally activated by returning @expr{-1@} from the //! @tt{main@} function and will then execute in the main thread. //! //! @ul //! @item //! When data arrives on the stream, @[read_cb] will be called with //! some or all of that data as the second argument.
a371252005-01-26Martin Stjernholm  //!
333fe42014-10-08Arne Goedeke  //! If the file is in buffer mode, the second argument will be a Buffer.
8923ca2014-09-03Per Hedbor  //! //! This will always be the same buffer, so data you do not use in //! one read callback can be simply left in the buffer, when new //! data arrives it will be appended //! //!
3bc55b2003-10-29Martin Stjernholm  //! @item //! When the stream has buffer space over for writing, @[write_cb] //! will be called so that you can write more data to it.
a371252005-01-26Martin Stjernholm  //! //! This callback is also called after the remote end of a socket
f3ec252005-01-26Martin Stjernholm  //! connection has closed the write direction. An attempt to write //! data to it in that case will generate a @[System.EPIPE] errno. //! If the remote end has closed both directions simultaneously //! (the usual case), Pike will first attempt to call @[close_cb], //! then this callback (unless @[close_cb] has closed the stream).
a371252005-01-26Martin Stjernholm  //!
333fe42014-10-08Arne Goedeke  //! If the file is in buffer mode, the second argument will be a Buffer.
8923ca2014-09-03Per Hedbor  //! //! You should add data to write to this buffer.
3bc55b2003-10-29Martin Stjernholm  //! @item //! When out-of-band data arrives on the stream, @[read_oob_cb] //! will be called with some or all of that data as the second //! argument.
a371252005-01-26Martin Stjernholm  //!
3bc55b2003-10-29Martin Stjernholm  //! @item //! When the stream allows out-of-band data to be sent, //! @[write_oob_cb] will be called so that you can write more //! out-of-band data to it.
a371252005-01-26Martin Stjernholm  //! //! If the OS doesn't separate the write events for normal and //! out-of-band data, Pike will try to call @[write_oob_cb] first. //! If it doesn't write anything, then @[write_cb] will be tried. //! This also means that @[write_oob_cb] might get called when the
f3ec252005-01-26Martin Stjernholm  //! remote end of a connection has closed the write direction.
a371252005-01-26Martin Stjernholm  //!
3bc55b2003-10-29Martin Stjernholm  //! @item
a371252005-01-26Martin Stjernholm  //! When an error or an end-of-stream in the read direction //! occurs, @[close_cb] will be called. @[errno] will return the //! error, or zero in the case of an end-of-stream. //! //! The name of this callback is rather unfortunate since it //! really has nothing to do with a close: The stream is still //! open when @[close_cb] is called (you might not be able to read //! and/or write to it, but you can still use things like //! @[query_address], and the underlying file descriptor is still //! allocated). Also, this callback will not be called for a local //! close, neither by a call to @[close] or by destructing this //! object. //!
f3ec252005-01-26Martin Stjernholm  //! Also, @[close_cb] will not be called if a remote close only //! occurs in the write direction; that is handled by @[write_cb] //! (or possibly @[write_oob_cb]).
a371252005-01-26Martin Stjernholm  //!
f3ec252005-01-26Martin Stjernholm  //! Events to @[read_cb] and @[close_cb] will be automatically //! deregistered if an end-of-stream occurs, and all events in the //! case of an error. I.e. there won't be any more calls to the //! callbacks unless they are reinstalled. This doesn't affect the
a371252005-01-26Martin Stjernholm  //! callback settings - @[query_read_callback] et al will still //! return the installed callbacks.
3bc55b2003-10-29Martin Stjernholm  //! @endul //!
f3ec252005-01-26Martin Stjernholm  //! If the stream is a socket performing a nonblocking connect (see //! @[open_socket] and @[connect]), a connection failure will call //! @[close_cb], and a successful connect will call either //! @[read_cb] or @[write_cb] as above. //!
3bc55b2003-10-29Martin Stjernholm  //! All callbacks will receive the @tt{id@} set by @[set_id] as //! first argument. //! //! If a callback returns @expr{-1@}, no other callback or call out //! will be called by the backend in that round. I.e. the caller of //! the backend will get control back right away. For the default //! backend that means it will immediately start another round and //! check files and call outs anew.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
65820a2012-05-02Bill Welliver  //! @param event_mask //! An event mask specifing bitwise OR of one or more event types to //! monitor, selected from @[Stdio.NOTE_WRITE] and friends.
3524712015-05-26Martin Nilsson  //!
3bc55b2003-10-29Martin Stjernholm  //! @note //! These functions do not set the file nonblocking.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
3bc55b2003-10-29Martin Stjernholm  //! @note
c6ac602009-04-25Martin Stjernholm  //! Callbacks are also set by @[set_callbacks] and //! @[set_nonblocking()].
e354d12002-03-02Marcus Agehall  //!
3bc55b2003-10-29Martin Stjernholm  //! @note
5e3bd42004-04-05Martin Stjernholm  //! After a callback has been called, it's disabled until it has //! accessed the stream accordingly, i.e. the @[write_cb] callback //! is disabled after it's been called until something has been //! written with @[write], and the @[write_oob_cb] callback is //! likewise disabled until something has been written with //! @[write_oob]. Since the data already has been read when the read //! callbacks are called, this effect is not noticeable for them.
3abdbd2004-04-05Martin Stjernholm  //! //! @note
3bc55b2003-10-29Martin Stjernholm  //! Installing callbacks means that you will start doing I/O on the //! stream from the thread running the backend. If you are running //! these set functions from another thread you must be prepared //! that the callbacks can be called immediately by the backend //! thread, so it might not be safe to continue using the stream in //! this thread.
3524712015-05-26Martin Nilsson  //!
3bc55b2003-10-29Martin Stjernholm  //! Because of that, it's useful to talk about "callback mode" when //! any callback is installed. In callback mode the stream should be //! seen as "bound" to the backend thread. For instance, it's only //! the backend thread that reliably can end callback mode before //! the stream is "handed over" to another thread.
ad6dec2003-10-24Martin Stjernholm  //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @note
3bc55b2003-10-29Martin Stjernholm  //! Callback mode has nothing to do with nonblocking mode - although //! the two often are used together they don't have to be.
0faed92003-07-22Henrik Grubbström (Grubba)  //! //! @note
3abdbd2004-04-05Martin Stjernholm  //! The file object will stay referenced from the backend object as //! long as there are callbacks that can receive events.
3bc55b2003-10-29Martin Stjernholm  //! //! @bugs //! Setting a close callback without a read callback currently only //! works when there's no risk of getting more data on the stream. //! Otherwise the close callback will be silently deregistered if //! data arrives.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
ca6bd02012-05-01Bill Welliver  //! @note //! fs_event callbacks only trigger on systems that support these events. //! Currently, this includes systems that use kqueue, such as Mac OS X, //! and various flavours of BSD. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @seealso
c6ac602009-04-25Martin Stjernholm  //! @[set_callbacks], @[set_nonblocking()], @[set_id()], //! @[set_backend], @[query_read_callback], @[query_write_callback],
3bc55b2003-10-29Martin Stjernholm  //! @[query_read_oob_callback], @[query_write_oob_callback], //! @[query_close_callback]
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
c6ac602009-04-25Martin Stjernholm #define SET(X,Y) ::set_##X ((___##X = (Y)) && __stdio_##X) #define _SET(X,Y) _fd->_##X=(___##X = (Y)) && __stdio_##X
ac0bf02014-09-15Per Hedbor  void set_callbacks (read_callback_t|void read_cb, write_callback_t|void write_cb, void|function(mixed:int) close_cb, void|function(mixed, string:int) read_oob_cb, void|function(mixed:int) write_oob_cb)
c6ac602009-04-25Martin Stjernholm  //! Installs all the specified callbacks at once. Use @[UNDEFINED] //! to keep the current setting for a callback. //! //! Like @[set_nonblocking], the callbacks are installed atomically. //! As opposed to @[set_nonblocking], this function does not do //! anything with the stream, and it doesn't even have to be open. //! //! @seealso //! @[set_read_callback], @[set_write_callback], //! @[set_read_oob_callback], @[set_write_oob_callback], //! @[set_close_callback], @[query_callbacks] { ::_disable_callbacks(); // Bypass the ::set_xxx_callback functions; we instead enable all // the event bits at once through the _enable_callbacks call at the end.
65340d2014-08-15Martin Nilsson  if (!undefinedp (read_cb))
c6ac602009-04-25Martin Stjernholm  _SET (read_callback, read_cb);
65340d2014-08-15Martin Nilsson  if (!undefinedp (write_cb))
c6ac602009-04-25Martin Stjernholm  _SET (write_callback, write_cb);
65340d2014-08-15Martin Nilsson  if (!undefinedp (close_cb) &&
c6ac602009-04-25Martin Stjernholm  (___close_callback = close_cb) && !___read_callback) _fd->_read_callback = __stdio_close_callback;
65340d2014-08-15Martin Nilsson  if (!undefinedp (read_oob_cb))
c6ac602009-04-25Martin Stjernholm  _SET (read_oob_callback, read_oob_cb);
65340d2014-08-15Martin Nilsson  if (!undefinedp (write_oob_cb))
c6ac602009-04-25Martin Stjernholm  _SET (write_oob_callback, write_oob_cb); ::_enable_callbacks(); }
ac0bf02014-09-15Per Hedbor  //! @decl read_callback_t query_read_callback() //! @decl write_callback_t query_write_callback()
3bc55b2003-10-29Martin Stjernholm  //! @decl function(mixed, string:int) query_read_oob_callback() //! @decl function(mixed:int) query_write_oob_callback() //! @decl function(mixed:int) query_close_callback()
c6ac602009-04-25Martin Stjernholm  //! @decl array(function(mixed,void|string:int)) query_callbacks()
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
3bc55b2003-10-29Martin Stjernholm  //! These functions return the currently installed callbacks for the //! respective events.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
c6ac602009-04-25Martin Stjernholm  //! @[query_callbacks] returns the callbacks in the same order as //! @[set_callbacks] and @[set_nonblocking] expect them. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @seealso
3bc55b2003-10-29Martin Stjernholm  //! @[set_nonblocking()], @[set_read_callback], //! @[set_write_callback], @[set_read_oob_callback],
c6ac602009-04-25Martin Stjernholm  //! @[set_write_oob_callback], @[set_close_callback], //! @[set_callbacks]
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @ignore
3bc55b2003-10-29Martin Stjernholm 
ac0bf02014-09-15Per Hedbor  void set_read_callback(read_callback_t read_cb)
b37f042001-11-22Henrik Grubbström (Grubba)  {
51f1ce2015-09-06Martin Nilsson  BE_WERR("setting read_callback to %O\n", read_cb);
b37f042001-11-22Henrik Grubbström (Grubba)  ::set_read_callback(((___read_callback = read_cb) && __stdio_read_callback) || (___close_callback && __stdio_close_callback)); }
ac0bf02014-09-15Per Hedbor  read_callback_t query_read_callback()
b37f042001-11-22Henrik Grubbström (Grubba)  { return ___read_callback; }
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
f3ec252005-01-26Martin Stjernholm #define CBFUNC(TYPE, X) \ void set_##X (TYPE l##X) \ { \
51f1ce2015-09-06Martin Nilsson  BE_WERR("setting " #X " to %O\n", l##X); \
f3ec252005-01-26Martin Stjernholm  SET( X , l##X ); \ } \ \ TYPE query_##X () \ { \ return ___##X; \ }
ac0bf02014-09-15Per Hedbor  CBFUNC(write_callback_t, write_callback)
f3ec252005-01-26Martin Stjernholm  CBFUNC(function(mixed|void,string|void:int), read_oob_callback) CBFUNC(function(mixed|void:int), write_oob_callback)
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
ca6bd02012-05-01Bill Welliver  void set_fs_event_callback(function(mixed|void,int:int) c, int event_mask) { ___fs_event_callback=c; if(c) { ::set_fs_event_callback(__stdio_fs_event_callback, event_mask); } else {
8923ca2014-09-03Per Hedbor  ::set_fs_event_callback(0, 0);
ca6bd02012-05-01Bill Welliver  } }
f3ec252005-01-26Martin Stjernholm  void set_close_callback(function(mixed|void:int) c) {
b37f042001-11-22Henrik Grubbström (Grubba)  ___close_callback=c; if (!___read_callback) { if (c) { ::set_read_callback(__stdio_close_callback); } else { ::set_read_callback(0); } } }
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
f3ec252005-01-26Martin Stjernholm  function(mixed|void:int) query_close_callback() { return ___close_callback; }
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
ca6bd02012-05-01Bill Welliver  function(mixed|void,int:int) query_fs_event_callback() { return ___fs_event_callback; } // this getter is provided by Stdio.Fd. // function(mixed|void:int) query_fs_event_callback() { return ___fs_event_callback; }
cb65012014-10-01Martin Nilsson  array(function(mixed,void|string|Buffer:int)) query_callbacks()
c6ac602009-04-25Martin Stjernholm  { return ({ ___read_callback, ___write_callback, ___close_callback, ___read_oob_callback, ___write_oob_callback, }); }
9eaf1d2008-06-28Martin Nilsson  protected void fix_internal_callbacks()
ef3ada2004-04-05Martin Stjernholm  {
5abe942004-04-07Henrik Grubbström (Grubba)  BE_WERR("fix_internal_callbacks()\n");
ef3ada2004-04-05Martin Stjernholm  ::set_read_callback ((___read_callback && __stdio_read_callback) || (___close_callback && __stdio_close_callback)); ::set_write_callback (___write_callback && __stdio_write_callback); ::set_read_oob_callback (___read_oob_callback && __stdio_read_oob_callback);
a8852e2004-04-06Henrik Grubbström (Grubba)  ::set_write_oob_callback (___write_oob_callback && __stdio_write_oob_callback);
ef3ada2004-04-05Martin Stjernholm  }
3bc55b2003-10-29Martin Stjernholm  //! @endignore
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function sets the @tt{id@} of this file. The @tt{id@} is mainly //! used as an identifier that is sent as the first argument to all
cbe8c92003-04-07Martin Nilsson  //! callbacks. The default @tt{id@} is @expr{0@} (zero). Another possible
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! use of the @tt{id@} is to hold all data related to this file in a //! mapping or array. //! //! @seealso //! @[query_id()] //! void set_id(mixed id) { ___id=id; } //! This function returns the @tt{id@} that has been set with @[set_id()]. //! //! @seealso //! @[set_id()] //!
7694021998-04-06Fredrik Hübinette (Hubbe)  mixed query_id() { return ___id; }
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
ac0bf02014-09-15Per Hedbor  //! @decl void set_nonblocking(read_callback_t read_callback, @ //! write_callback_t write_callback, @
ad6dec2003-10-24Martin Stjernholm  //! function(mixed:int) close_callback)
ac0bf02014-09-15Per Hedbor  //! @decl void set_nonblocking(read_callback_t read_callback, @ //! write_callback_t write_callback, @
ad6dec2003-10-24Martin Stjernholm  //! function(mixed:int) close_callback, @ //! function(mixed, string:int) read_oob_callback, @ //! function(mixed:int) write_oob_callback)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl void set_nonblocking() //!
3bc55b2003-10-29Martin Stjernholm  //! This function sets a stream to nonblocking mode and installs the //! specified callbacks. See the @expr{set_*_callback@} functions //! for details about them. If no arguments are given, the callbacks //! will be cleared.
ad6dec2003-10-24Martin Stjernholm  //!
0faed92003-07-22Henrik Grubbström (Grubba)  //! @note
3bc55b2003-10-29Martin Stjernholm  //! As opposed to calling the set callback functions separately, //! this function will set all the callbacks and nonblocking mode //! atomically so that no callback gets called in between. That //! avoids races in case the backend is executed by another thread.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @note
15a3d22003-10-23Henrik Grubbström (Grubba)  //! Out-of-band data was not be supported on Pike 0.5 and earlier, //! and not on Pike 0.6 through 7.4 if they were compiled with the
0faed92003-07-22Henrik Grubbström (Grubba)  //! option @tt{'--without-oob'@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso
c6ac602009-04-25Martin Stjernholm  //! @[set_blocking()], @[set_callbacks], @[set_read_callback()],
3bc55b2003-10-29Martin Stjernholm  //! @[set_write_callback()], @[set_read_oob_callback()], //! @[set_write_oob_callback()], @[set_close_callback()] //! @[set_nonblocking_keep_callbacks()], //! @[set_blocking_keep_callbacks()]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
c46feb1998-04-05Fredrik Hübinette (Hubbe)  void set_nonblocking(mixed|void rcb, mixed|void wcb, mixed|void ccb, mixed|void roobcb,
15a3d22003-10-23Henrik Grubbström (Grubba)  mixed|void woobcb)
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
41a8b01998-09-01Fredrik Hübinette (Hubbe)  CHECK_OPEN();
0a970a1998-07-26Fredrik Hübinette (Hubbe)  ::_disable_callbacks(); // Thread safing
d947872009-04-25Martin Stjernholm  // Bypass the ::set_xxx_callback functions; we instead enable all // the event bits at once through the _enable_callbacks call at the end.
0a970a1998-07-26Fredrik Hübinette (Hubbe)  _SET(read_callback,rcb); _SET(write_callback,wcb);
b37f042001-11-22Henrik Grubbström (Grubba)  if ((___close_callback = ccb) && (!rcb)) {
d947872009-04-25Martin Stjernholm  _fd->_read_callback = __stdio_close_callback;
b37f042001-11-22Henrik Grubbström (Grubba)  }
217a001998-04-14Fredrik Hübinette (Hubbe) 
0a970a1998-07-26Fredrik Hübinette (Hubbe)  _SET(read_oob_callback,roobcb); _SET(write_oob_callback,woobcb);
d947872009-04-25Martin Stjernholm 
0a970a1998-07-26Fredrik Hübinette (Hubbe) #ifdef __STDIO_DEBUG if(mixed x=catch { ::set_nonblocking(); }) {
3524712015-05-26Martin Nilsson  x[0]+=(__closed_backtrace ?
0a970a1998-07-26Fredrik Hübinette (Hubbe)  sprintf("File was closed from:\n %-=200s\n",__closed_backtrace) :
ef3ada2004-04-05Martin Stjernholm  "This file has never been open.\n" );
0a970a1998-07-26Fredrik Hübinette (Hubbe)  throw(x); } #else
c46feb1998-04-05Fredrik Hübinette (Hubbe)  ::set_nonblocking();
0a970a1998-07-26Fredrik Hübinette (Hubbe) #endif
d947872009-04-25Martin Stjernholm 
0a970a1998-07-26Fredrik Hübinette (Hubbe)  ::_enable_callbacks();
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
3bc55b2003-10-29Martin Stjernholm  //! This function clears all callbacks and sets a stream to blocking //! mode. i.e. reading, writing and closing will wait until data has //! been transferred before returning.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
0faed92003-07-22Henrik Grubbström (Grubba)  //! @note
3bc55b2003-10-29Martin Stjernholm  //! The callbacks are cleared and blocking mode is set in one atomic //! operation, so no callback gets called in between if the backend //! is running in another thread. //! //! Even so, if the stream is in callback mode (i.e. if any //! callbacks are installed) then only the backend thread can use //! this function reliably; it might otherwise already be running in //! a callback which is about to call e.g. @[write] when the stream //! becomes blocking.
0faed92003-07-22Henrik Grubbström (Grubba)  //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @seealso
0faed92003-07-22Henrik Grubbström (Grubba)  //! @[set_nonblocking()], @[set_nonblocking_keep_callbacks()], //! @[set_blocking_keep_callbacks()]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
c46feb1998-04-05Fredrik Hübinette (Hubbe)  void set_blocking() {
41a8b01998-09-01Fredrik Hübinette (Hubbe)  CHECK_OPEN();
277d8b1999-06-29Martin Stjernholm  ::_disable_callbacks(); // Thread safing
217a001998-04-14Fredrik Hübinette (Hubbe)  SET(read_callback,0); SET(write_callback,0); ___close_callback=0; SET(read_oob_callback,0); SET(write_oob_callback,0);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  ::set_blocking();
4266062009-03-19Henrik Grubbström (Grubba)  // NOTE: _enable_callbacks() can throw in only one case; // when callback operations aren't supported, which // we don't care about in this case, since we've // just cleared all the callbacks anyway. catch { ::_enable_callbacks(); };
c46feb1998-04-05Fredrik Hübinette (Hubbe)  }
7892e71999-04-30Fredrik Hübinette (Hubbe) 
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl void set_nonblocking_keep_callbacks() //! @decl void set_blocking_keep_callbacks()
0faed92003-07-22Henrik Grubbström (Grubba)  //! Toggle between blocking and nonblocking, //! without changing the callbacks. //! //! @seealso //! @[set_nonblocking()], @[set_blocking()]
07d9352014-09-05Per Hedbor 
c3b04c2001-03-10Mirar (Pontus Hagland)  void set_blocking_keep_callbacks() { CHECK_OPEN(); ::set_blocking(); } void set_nonblocking_keep_callbacks() { CHECK_OPEN(); ::set_nonblocking(); }
8923ca2014-09-03Per Hedbor 
c071bc2017-11-05Henrik Grubbström (Grubba)  protected void _destruct()
7892e71999-04-30Fredrik Hübinette (Hubbe)  {
c071bc2017-11-05Henrik Grubbström (Grubba)  BE_WERR("_destruct()");
ba6d7b2001-04-19Martin Stjernholm  register_close_file (open_file_id);
7892e71999-04-30Fredrik Hübinette (Hubbe)  }
7dc3162001-04-27Henrik Grubbström (Grubba) }
c46feb1998-04-05Fredrik Hübinette (Hubbe) 
de411a2002-04-01Martin Nilsson //! Handles listening to socket ports. Whenever you need a bound //! socket that is open and listens for connections you should //! use this program.
c46feb1998-04-05Fredrik Hübinette (Hubbe) class Port {
36bff11998-05-27Henrik Grubbström (Grubba)  inherit _port;
5a2a2c2000-09-10Per Hedbor 
9eaf1d2008-06-28Martin Nilsson  protected int|string debug_port; protected string debug_ip;
5a2a2c2000-09-10Per Hedbor 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf( int f )
5a2a2c2000-09-10Per Hedbor  {
a8852e2004-04-06Henrik Grubbström (Grubba)  return f=='O' && sprintf( "%O(%s:%O)", this_program, debug_ip||"", debug_port );
5a2a2c2000-09-10Per Hedbor  }
f6b99f2009-02-24Henrik Grubbström (Grubba)  //! Factory creating empty @[Fd] objects. //! //! This function is called by @[accept()] when it needs to create //! a new file. protected Fd fd_factory() { return File()->_fd; }
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl void create()
3c0d582003-04-22Marcus Comstedt  //! @decl void create(int|string port) //! @decl void create(int|string port, function accept_callback) //! @decl void create(int|string port, function accept_callback, string ip)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl void create("stdin") //! @decl void create("stdin", function accept_callback) //!
cbe8c92003-04-07Martin Nilsson  //! If the first argument is other than @expr{"stdin"@} the arguments will
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! be passed to @[bind()]. //!
cbe8c92003-04-07Martin Nilsson  //! When create is called with @expr{"stdin"@} as the first argument, a //! socket is created out of the file descriptor @expr{0@}. This is only
8665eb2017-02-12Chris Angelico  //! useful if it actually is a socket to begin with, and is equivalent to //! creating a port and initializing it with @[listen_fd](0).
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso //! @[bind]
9eaf1d2008-06-28Martin Nilsson  protected void create( string|int|void p,
9026ad2003-12-15Henrik Grubbström (Grubba)  void|mixed cb, string|void ip )
5a2a2c2000-09-10Per Hedbor  { debug_ip = (ip||"ANY"); debug_port = p;
f9b5102004-04-11Henrik Grubbström (Grubba)  if( cb || ip )
5a2a2c2000-09-10Per Hedbor  if( ip ) ::create( p, cb, ip ); else ::create( p, cb ); else ::create( p ); }
55589d2014-09-03Per Hedbor  int bind(int|string port, void|function accept_callback, void|string ip, int|void shared) {
3607962004-03-13Marcus Agehall  // Needed to fix _sprintf(). debug_ip = (ip||"ANY");
fb0bfb2004-03-13Marcus Agehall  debug_port = port;
55589d2014-09-03Per Hedbor  return ::bind(port, accept_callback, ip, shared);
3607962004-03-13Marcus Agehall  }
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function completes a connection made from a remote machine to //! this port. It returns a two-way stream in the form of a clone of
0faed92003-07-22Henrik Grubbström (Grubba)  //! @[Stdio.File]. The new file is by initially set to blocking mode.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso //! @[Stdio.File] //!
5a2a2c2000-09-10Per Hedbor  File accept()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
f6b99f2009-02-24Henrik Grubbström (Grubba)  if(object(Fd) x=::accept())
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
f6b99f2009-02-24Henrik Grubbström (Grubba)  File y = function_object(x->read);
5a2a2c2000-09-10Per Hedbor  y->_setup_debug( "socket", x->query_address() );
c46feb1998-04-05Fredrik Hübinette (Hubbe)  return y; } return 0; } }
58fcd51998-01-27Fredrik Hübinette (Hubbe) 
0faed92003-07-22Henrik Grubbström (Grubba) //! @[Stdio.FILE] is a buffered version of @[Stdio.File], it inherits //! @[Stdio.File] and has most of the functionality of @[Stdio.File]. //! However, it has an input buffer that allows line-by-line input. //! //! It also has support for automatic charset conversion for both input //! and output (see @[Stdio.FILE()->set_charset()]). //! //! @note //! The output part of @[Stdio.FILE] is currently not buffered.
63ccac2000-12-03Per Hedbor class FILE { inherit File : file;
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
4266062009-03-19Henrik Grubbström (Grubba)  // This is needed since it was overloaded in File above. protected Fd fd_factory() { return FILE()->_fd; }
63ccac2000-12-03Per Hedbor  /* Private functions / buffers etc. */
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
63ccac2000-12-03Per Hedbor  private string b="";
12c9652003-07-10Henrik Grubbström (Grubba)  private int bpos=0, lp; // Contains a prefix of b splitted on "\n". // Note that the last element of the array is a partial line, // and should not be used.
d106052005-04-08Martin Nilsson  private array(string) cached_lines = ({});
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
ba47542001-06-16Per Hedbor  private function(string:string) output_conversion, input_conversion;
3524712015-05-26Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf( int type, mapping flags )
63ccac2000-12-03Per Hedbor  { return ::_sprintf( type, flags ); }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
9aee552009-04-25Martin Stjernholm  inline private int low_get_data()
12c9652003-07-10Henrik Grubbström (Grubba)  {
809a322009-12-03Martin Stjernholm  string s = file::read(DATA_CHUNK_SIZE,1);
12c9652003-07-10Henrik Grubbström (Grubba)  if(s && strlen(s)) { if( input_conversion ) { s = input_conversion( s ); } b+=s; return 1; }
ad66752014-05-26Martin Nilsson  return 0;
12c9652003-07-10Henrik Grubbström (Grubba)  }
3524712015-05-26Martin Nilsson 
9aee552009-04-25Martin Stjernholm  inline private int get_data()
63ccac2000-12-03Per Hedbor  {
4f509f2000-12-10Per Hedbor  if( bpos ) {
63ccac2000-12-03Per Hedbor  b = b[ bpos .. ];
4f509f2000-12-10Per Hedbor  bpos=0; }
12c9652003-07-10Henrik Grubbström (Grubba)  return low_get_data(); } // Update cached_lines and lp // Return 0 at end of file, 1 otherwise. // At exit cached_lines contains at least one string, // and lp is set to zero.
9aee552009-04-25Martin Stjernholm  inline private int get_lines()
12c9652003-07-10Henrik Grubbström (Grubba)  { if( bpos )
4f509f2000-12-10Per Hedbor  {
12c9652003-07-10Henrik Grubbström (Grubba)  b = b[ bpos .. ]; bpos=0; } int start = 0; while ((search(b, "\n", start) == -1) && ((start = sizeof(b)), low_get_data())) ; cached_lines = b/"\n"; lp = 0; return sizeof(cached_lines) > 1;
63ccac2000-12-03Per Hedbor  }
5a2a2c2000-09-10Per Hedbor 
12c9652003-07-10Henrik Grubbström (Grubba)  // NB: Caller is responsible for clearing cached_lines and lp.
9aee552009-04-25Martin Stjernholm  inline private string extract(int bytes, int|void skip)
63ccac2000-12-03Per Hedbor  { string s; s=b[bpos..bpos+bytes-1];
12c9652003-07-10Henrik Grubbström (Grubba)  if ((bpos += bytes+skip) > sizeof(b)) { bpos = 0; b = ""; }
63ccac2000-12-03Per Hedbor  return s; } /* Public functions. */
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
5890472010-10-11Per Hedbor  void set_charset( string|void charset )
ba47542001-06-16Per Hedbor  //! Sets the input and output charset of this file to the specified
5890472010-10-11Per Hedbor  //! @[charset]. If @[charset] is 0 or not specified the environment //! is used to try to detect a suitable charset.
0faed92003-07-22Henrik Grubbström (Grubba)  //!
5890472010-10-11Per Hedbor  //! The default charset if this function is not called is //! @tt{"ISO-8859-1"@}.
e604922008-04-28Henrik Grubbström (Grubba)  //! //! @fixme //! Consider using one of
e487132008-04-28Henrik Grubbström (Grubba)  //! ISO-IR-196 (@tt{"\e%G"@} - switch to UTF-8 with return) //! or ISO-IR-190 (@tt{"\e%/G"@} - switch to UTF-8 level 1 no return) //! or ISO-IR-191 (@tt{"\e%/H"@} - switch to UTF-8 level 2 no return) //! or ISO-IR-192 (@tt{"\e%/I"@} - switch to UTF-8 level 3 no return) //! or ISO-IR-193 (@tt{"\e%/J"@} - switch to UTF-16 level 1 no return) //! or ISO-IR-194 (@tt{"\e%/K"@} - switch to UTF-16 level 2 no return) //! or ISO-IR-195 (@tt{"\e%/L"@} - switch to UTF-16 level 3 no return)
e604922008-04-28Henrik Grubbström (Grubba)  //! or ISO-IR-162 (@tt{"\e%/@@"@} - switch to UCS-2 level 1) //! or ISO-IR-163 (@tt{"\e%/A"@} - switch to UCS-4 level 1) //! or ISO-IR-174 (@tt{"\e%/C"@} - switch to UCS-2 level 2) //! or ISO-IR-175 (@tt{"\e%/D"@} - switch to UCS-4 level 2) //! or ISO-IR-176 (@tt{"\e%/E"@} - switch to UCS-2 level 3) //! or ISO-IR-177 (@tt{"\e%/F"@} - switch to UCS-4 level 3) //! or ISO-IR-178 (@tt{"\e%B"@} - switch to UTF-1) //! automatically to encode wide strings.
ba47542001-06-16Per Hedbor  {
5890472010-10-11Per Hedbor  if( !charset ) // autodetect. { if( getenv("CHARSET") ) charset = getenv("CHARSET"); else if( getenv("LANG") ) sscanf(getenv("LANG"), "%*s.%s", charset ); if( !charset ) return; }
ba47542001-06-16Per Hedbor  charset = lower_case( charset ); if( charset != "iso-8859-1" && charset != "ascii") {
4309502017-08-22Martin Nilsson  object in = Pike.Lazy.Charset.decoder( charset ); object out = Pike.Lazy.Charset.encoder( charset );
ba47542001-06-16Per Hedbor  input_conversion =
d106052005-04-08Martin Nilsson  [function(string:string)]lambda( string s ) {
ba47542001-06-16Per Hedbor  return in->feed( s )->drain(); }; output_conversion =
d106052005-04-08Martin Nilsson  [function(string:string)]lambda( string s ) {
ba47542001-06-16Per Hedbor  return out->feed( s )->drain(); }; } else input_conversion = output_conversion = 0; }
0db0302002-11-26Henrik Grubbström (Grubba)  //! Read one line of input with support for input conversion.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
60772e2008-12-09Henrik Grubbström (Grubba)  //! @param not_all //! Set this parameter to ignore partial lines at EOF. This //! is useful for eg monitoring a growing logfile. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @returns
cbe8c92003-04-07Martin Nilsson  //! This function returns the line read if successful, and @expr{0@} if
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! no more lines are available. //! //! @seealso
0db0302002-11-26Henrik Grubbström (Grubba)  //! @[ngets()], @[read()], @[line_iterator()], @[set_charset()]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
60772e2008-12-09Henrik Grubbström (Grubba)  string gets(int(0..1)|void not_all)
63ccac2000-12-03Per Hedbor  {
12c9652003-07-10Henrik Grubbström (Grubba)  string r; if( (sizeof(cached_lines) <= lp+1) && !get_lines()) { // EOF // NB: lp is always zero here.
60772e2008-12-09Henrik Grubbström (Grubba)  if (sizeof(r = cached_lines[0]) && !not_all) {
12c9652003-07-10Henrik Grubbström (Grubba)  cached_lines = ({}); b = ""; bpos = 0; return r;
8c58c42001-04-07Mirar (Pontus Hagland)  }
63ccac2000-12-03Per Hedbor  return 0;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  }
12c9652003-07-10Henrik Grubbström (Grubba)  bpos += sizeof(r = cached_lines[lp++]) + 1; return r;
63ccac2000-12-03Per Hedbor  }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
707b922014-09-23Per Hedbor  int seek(int pos, string|void how)
63ccac2000-12-03Per Hedbor  {
07d8062008-07-14Stephen R. van den Berg  bpos=0; b=""; cached_lines = ({}); lp=0;
707b922014-09-23Per Hedbor  if( how ) return file::seek(pos,[string]how);
63ccac2000-12-03Per Hedbor  return file::seek(pos); }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
c0a32d2008-07-12Stephen R. van den Berg  int(-1..1) peek(void|int|float timeout) { if(sizeof(b)-bpos) return 1; return file::peek(timeout); }
63ccac2000-12-03Per Hedbor  int tell() { return file::tell()-sizeof(b)+bpos; }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
63ccac2000-12-03Per Hedbor  int close(void|string mode) { bpos=0; b=""; if(!mode) mode="rw"; file::close(mode); }
e835302000-12-03Mirar (Pontus Hagland) 
63ccac2000-12-03Per Hedbor  int open(string file, void|string mode) { bpos=0; b=""; if(!mode) mode="rwc"; return file::open(file,mode); }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
0e77e92008-12-14Marcus Comstedt  int open_socket(int|string|void port, string|void address, int|string|void family_hint)
63ccac2000-12-03Per Hedbor  { bpos=0; b="";
65340d2014-08-15Martin Nilsson  if(undefinedp(port))
3563352003-03-08Martin Nilsson  return file::open_socket();
0e77e92008-12-14Marcus Comstedt  return file::open_socket(port, address, family_hint);
63ccac2000-12-03Per Hedbor  }
2eedf71997-05-16Wilhelm Köhler 
12c9652003-07-10Henrik Grubbström (Grubba)  //! Get @[n] lines. //! //! @param n //! Number of lines to get, or all remaining if zero.
60772e2008-12-09Henrik Grubbström (Grubba)  //! //! @param not_all //! Set this parameter to ignore partial lines at EOF. This //! is useful for eg monitoring a growing logfile. array(string) ngets(void|int(1..) n, int(0..1)|void not_all)
63ccac2000-12-03Per Hedbor  {
12c9652003-07-10Henrik Grubbström (Grubba)  array(string) res;
3524712015-05-26Martin Nilsson  if (!n)
2fbb682001-04-07Mirar (Pontus Hagland)  {
12c9652003-07-10Henrik Grubbström (Grubba)  res=read()/"\n";
60772e2008-12-09Henrik Grubbström (Grubba)  if (res[-1]=="" || not_all) return res[..<1];
12c9652003-07-10Henrik Grubbström (Grubba)  return res;
2fbb682001-04-07Mirar (Pontus Hagland)  }
12c9652003-07-10Henrik Grubbström (Grubba)  if (n < 0) return ({}); res = ({}); do { array(string) delta; if (lp + n < sizeof(cached_lines)) { delta = cached_lines[lp..(lp += n)-1]; bpos += `+(@sizeof(delta[*]), sizeof(delta)); return res + delta; }
8a531a2006-11-04Martin Nilsson  delta = cached_lines[lp..<1];
12c9652003-07-10Henrik Grubbström (Grubba)  bpos += `+(@sizeof(delta[*]), sizeof(delta)); res += delta; // NB: lp and cached_lines are reset by get_lines(). } while(get_lines()); // EOF, and we want more lines... // NB: At this point lp is always zero, and // cached_lines contains a single string.
60772e2008-12-09Henrik Grubbström (Grubba)  if (sizeof(cached_lines[0]) && !not_all) {
12c9652003-07-10Henrik Grubbström (Grubba)  // Return the partial line too. res += cached_lines;
60772e2008-12-09Henrik Grubbström (Grubba)  b = ""; bpos = 0; cached_lines = ({});
54dd9b1997-04-10Fredrik Hübinette (Hubbe)  }
12c9652003-07-10Henrik Grubbström (Grubba)  if (!sizeof(res)) return 0;
63ccac2000-12-03Per Hedbor  return res; }
ad66752014-05-26Martin Nilsson  //! Same as @[Stdio.File()->pipe()], but returns an @[Stdio.FILE] //! object.
4266062009-03-19Henrik Grubbström (Grubba)  //!
ad66752014-05-26Martin Nilsson  //! @seealso //! @[Stdio.File()->pipe()] FILE pipe(void|int flags)
63ccac2000-12-03Per Hedbor  {
8846ad2001-01-27Per Hedbor  bpos=0; cached_lines=({}); lp=0;
63ccac2000-12-03Per Hedbor  b=""; return query_num_arg() ? file::pipe(flags) : file::pipe(); }
59db4f2013-06-11Martin Nilsson #if constant(_Stdio.__HAVE_OPENAT__)
94fb5d2008-03-07Henrik Grubbström (Grubba)  //! @decl FILE openat(string filename, string mode) //! @decl FILE openat(string filename, string mode, int mask) //!
ad66752014-05-26Martin Nilsson  //! Same as @[Stdio.File()->openat()], but returns an @[Stdio.FILE]
94fb5d2008-03-07Henrik Grubbström (Grubba)  //! object. //! //! @seealso //! @[Stdio.File()->openat()] FILE openat(string filename, string mode, int|void mask) { if(query_num_arg()<3) mask = 0777; if(Fd fd=[object(Fd)]_fd->openat(filename, mode, mask)) {
f6b99f2009-02-24Henrik Grubbström (Grubba)  FILE o = function_object(fd->read);
cb1d132009-02-22Henrik Grubbström (Grubba)  string path = combine_path(debug_file||"", filename); o->_setup_debug(path, mode, mask); register_open_file(path, o->open_file_id, backtrace()); return o; }
ad66752014-05-26Martin Nilsson  return 0;
94fb5d2008-03-07Henrik Grubbström (Grubba)  }
550f192008-03-07Henrik Grubbström (Grubba) #endif
ad66752014-05-26Martin Nilsson 
0faed92003-07-22Henrik Grubbström (Grubba)  int assign(File|FILE foo)
63ccac2000-12-03Per Hedbor  {
8846ad2001-01-27Per Hedbor  bpos=0; cached_lines=({}); lp=0;
63ccac2000-12-03Per Hedbor  b=""; return ::assign(foo); }
54dd9b1997-04-10Fredrik Hübinette (Hubbe) 
5a2a2c2000-09-10Per Hedbor  FILE dup()
c46feb1998-04-05Fredrik Hübinette (Hubbe)  {
5a2a2c2000-09-10Per Hedbor  FILE o=FILE();
83f53a2003-06-27Martin Nilsson  o->assign(this);
c46feb1998-04-05Fredrik Hübinette (Hubbe)  return o; }
63ccac2000-12-03Per Hedbor  void set_nonblocking() { error("Cannot use nonblocking IO with buffered files.\n"); }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
0db0302002-11-26Henrik Grubbström (Grubba)  //! Write @[what] with support for output_conversion. //! //! @seealso //! @[Stdio.File()->write()]
cf9eee2001-06-16Per Hedbor  int write( array(string)|string what, mixed ... fmt )
ba47542001-06-16Per Hedbor  { if( output_conversion )
7427622001-06-16Per Hedbor  { if( sizeof( fmt ) ) { if( arrayp( what ) ) what *="";
d106052005-04-08Martin Nilsson  what = sprintf( [string]what, @fmt );
7427622001-06-16Per Hedbor  }
ba47542001-06-16Per Hedbor  if( arrayp( what ) ) what = map( what, output_conversion ); else
d106052005-04-08Martin Nilsson  what = output_conversion( [string]what );
7427622001-06-16Per Hedbor  return ::write( what ); } return ::write( what,@fmt );
ba47542001-06-16Per Hedbor  }
b9bd642001-07-16Henrik Grubbström (Grubba) 
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function does approximately the same as:
e5ef062003-04-01Martin Nilsson  //! @expr{@[write](@[sprintf](@[format],@@@[data]))@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @seealso //! @[write()], @[sprintf()] //! int printf(string format, mixed ... data)
63ccac2000-12-03Per Hedbor  {
8846ad2001-01-27Per Hedbor  return ::write(format,@data);
63ccac2000-12-03Per Hedbor  }
49bbfd2001-06-16Per Hedbor  function(:string) read_function(int nbytes) {
d9ada12014-09-04Per Hedbor  return lambda(){ return read( nbytes); };
49bbfd2001-06-16Per Hedbor  }
3524712015-05-26Martin Nilsson  //! Returns an iterator that will loop over the lines in this file.
731b0d2002-08-27Henrik Grubbström (Grubba)  //! //! @seealso //! @[line_iterator()]
9eaf1d2008-06-28Martin Nilsson  protected object _get_iterator()
731b0d2002-08-27Henrik Grubbström (Grubba)  { if( input_conversion )
809a322009-12-03Martin Stjernholm  return String.SplitIterator( "",'\n',1,read_function(DATA_CHUNK_SIZE));
731b0d2002-08-27Henrik Grubbström (Grubba)  // This one is about twice as fast, but it's way less flexible.
809a322009-12-03Martin Stjernholm  return __builtin.file_line_iterator( read_function(DATA_CHUNK_SIZE) );
731b0d2002-08-27Henrik Grubbström (Grubba)  }
ba47542001-06-16Per Hedbor  object line_iterator( int|void trim )
3524712015-05-26Martin Nilsson  //! Returns an iterator that will loop over the lines in this file.
0faed92003-07-22Henrik Grubbström (Grubba)  //! If @[trim] is true, all @tt{'\r'@} characters will be removed //! from the input.
731b0d2002-08-27Henrik Grubbström (Grubba)  //!
a171772005-02-02Per Hedbor  //! @note //! It's not supported to call this method more than once //! unless a call to @[seek] is done in advance. Also note that it's //! not possible to intermingle calls to @[read], @[gets] or other //! functions that read data with the line iterator, it will produce //! unexpected results since the internal buffer in the iterator will not //! contain sequential file-data in those cases.
3524712015-05-26Martin Nilsson  //!
731b0d2002-08-27Henrik Grubbström (Grubba)  //! @seealso //! @[_get_iterator()]
49bbfd2001-06-16Per Hedbor  { if( trim )
809a322009-12-03Martin Stjernholm  return String.SplitIterator( "",(<'\n','\r'>),1, read_function(DATA_CHUNK_SIZE));
731b0d2002-08-27Henrik Grubbström (Grubba)  return _get_iterator();
49bbfd2001-06-16Per Hedbor  }
0faed92003-07-22Henrik Grubbström (Grubba)  //! Read @[bytes] (wide-) characters with buffering and support for //! input conversion.
0db0302002-11-26Henrik Grubbström (Grubba)  //! //! @seealso
4d9f552008-07-14Stephen R. van den Berg  //! @[Stdio.File()->read()], @[set_charset()], @[unread()]
63ccac2000-12-03Per Hedbor  string read(int|void bytes,void|int(0..1) now) { if (!query_num_arg()) { bytes = 0x7fffffff; } /* Optimization - Hubbe */
809a322009-12-03Martin Stjernholm  if(!sizeof(b) && bytes > DATA_CHUNK_SIZE) {
0faed92003-07-22Henrik Grubbström (Grubba)  if (input_conversion) { // NOTE: This may depending on the charset return less // characters than requested. // FIXME: Does this handle EOF correctly?
0db0302002-11-26Henrik Grubbström (Grubba)  return input_conversion(::read(bytes, now));
0faed92003-07-22Henrik Grubbström (Grubba)  }
63ccac2000-12-03Per Hedbor  return ::read(bytes, now);
0db0302002-11-26Henrik Grubbström (Grubba)  }
63ccac2000-12-03Per Hedbor 
12c9652003-07-10Henrik Grubbström (Grubba)  cached_lines = ({}); lp = 0; while(sizeof(b) - bpos < bytes) {
63ccac2000-12-03Per Hedbor  if(!get_data()) { // EOF.
12c9652003-07-10Henrik Grubbström (Grubba)  // NB: get_data() sets bpos to zero. string res = b;
63ccac2000-12-03Per Hedbor  b = ""; return res;
7543bf1998-06-28Henrik Grubbström (Grubba)  }
63ccac2000-12-03Per Hedbor  else if (now) break;
12c9652003-07-10Henrik Grubbström (Grubba)  }
e114b51999-11-29Fredrik Hübinette (Hubbe) 
63ccac2000-12-03Per Hedbor  return extract(bytes); }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function puts a string back in the input buffer. The string //! can then be read with eg @[read()], @[gets()] or @[getchar()]. //!
6e391c2008-07-12Stephen R. van den Berg  //! @seealso
4d9f552008-07-14Stephen R. van den Berg  //! @[read()], @[gets()], @[getchar()], @[ungets()]
6e391c2008-07-12Stephen R. van den Berg  //!
4d9f552008-07-14Stephen R. van den Berg  void unread(string s)
6e391c2008-07-12Stephen R. van den Berg  { cached_lines = ({}); lp = 0; b=s+b[bpos..]; bpos=0; }
60772e2008-12-09Henrik Grubbström (Grubba)  //! This function puts a line back in the input buffer. The line
6e391c2008-07-12Stephen R. van den Berg  //! can then be read with eg @[read()], @[gets()] or @[getchar()]. //!
12c9652003-07-10Henrik Grubbström (Grubba)  //! @note
6e391c2008-07-12Stephen R. van den Berg  //! The string is autoterminated by an extra line-feed.
12c9652003-07-10Henrik Grubbström (Grubba)  //!
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @seealso
4d9f552008-07-14Stephen R. van den Berg  //! @[read()], @[gets()], @[getchar()], @[unread()]
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! void ungets(string s)
63ccac2000-12-03Per Hedbor  {
1a70c72003-12-01Stephen R. van den Berg  if(sizeof(cached_lines)>lp) cached_lines = s/"\n" + cached_lines[lp..]; else cached_lines = ({});
12c9652003-07-10Henrik Grubbström (Grubba)  lp = 0; b=s+"\n"+b[bpos..]; bpos=0;
63ccac2000-12-03Per Hedbor  }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
79b21c2008-07-14Stephen R. van den Berg  private protected final int getchar_get_data() { b = ""; bpos=0; return low_get_data(); } private protected final void getchar_updatelinecache() { if(sizeof(cached_lines)>lp+1 && sizeof(cached_lines[lp])) cached_lines = ({cached_lines[lp][1..]}) + cached_lines[lp+1..]; else cached_lines = ({}); lp=0; }
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! This function returns one character from the input stream. //! //! @returns
0faed92003-07-22Henrik Grubbström (Grubba)  //! Returns the ISO-10646 (Unicode) value of the character.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! //! @note
0faed92003-07-22Henrik Grubbström (Grubba)  //! Returns an @expr{int@} and not a @expr{string@} of length 1.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //!
79b21c2008-07-14Stephen R. van den Berg  inline int getchar()
63ccac2000-12-03Per Hedbor  {
79b21c2008-07-14Stephen R. van den Berg  if(sizeof(b) - bpos <= 0 && !getchar_get_data())
1a70c72003-12-01Stephen R. van den Berg  return -1;
79b21c2008-07-14Stephen R. van den Berg  if(sizeof(cached_lines)) getchar_updatelinecache();
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
63ccac2000-12-03Per Hedbor  return b[bpos++]; }
7dc3162001-04-27Henrik Grubbström (Grubba) }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
d106052005-04-08Martin Nilsson //! An instance of @tt{FILE("stderr")@}, the standard error stream. Use this //! when you want to output error messages. //! //! @seealso //! @[predef::werror()] FILE stderr=FILE("stderr"); //! An instance of @tt{FILE("stdout")@}, the standatd output stream. Use this //! when you want to write anything to the standard output. //! //! @seealso //! @[predef::write()] FILE stdout=FILE("stdout"); //! An instance of @tt{FILE("stdin")@}, the standard input stream. Use this //! when you want to read anything from the standard input. //! This example will read lines from standard input for as long as there //! are more lines to read. Each line will then be written to stdout together //! with the line number. We could use @[Stdio.stdout.write()] instead //! of just @[write()], since they are the same function. //! //! @example //! int main() //! { //! int line; //! while(string s=Stdio.stdin.gets()) //! write("%5d: %s\n", line++, s); //! } FILE stdin=FILE("stdin");
ba6d7b2001-04-19Martin Stjernholm #ifdef TRACK_OPEN_FILES
9eaf1d2008-06-28Martin Nilsson protected mapping(string|int:array) open_files = ([]); protected mapping(string:int) registering_files = ([]); protected int next_open_file_id = 1;
ba6d7b2001-04-19Martin Stjernholm 
9eaf1d2008-06-28Martin Nilsson protected void register_open_file (string file, int id, array backtrace)
ba6d7b2001-04-19Martin Stjernholm { file = combine_path (getcwd(), file);
820f072002-03-25Martin Stjernholm  if (!registering_files[file]) { // Avoid the recursion which might occur when the backtrace is formatted. registering_files[file] = 1; open_files[id] =
8a531a2006-11-04Martin Nilsson  ({file, describe_backtrace (backtrace[..<1])});
820f072002-03-25Martin Stjernholm  m_delete (registering_files, file); } else open_files[id] = ({file, "Cannot describe backtrace due to recursion.\n"});
ba6d7b2001-04-19Martin Stjernholm  if (!open_files[file]) open_files[file] = ({id}); else open_files[file] += ({id}); }
9eaf1d2008-06-28Martin Nilsson protected void register_close_file (int id)
ba6d7b2001-04-19Martin Stjernholm { if (open_files[id]) { string file = open_files[id][0]; open_files[file] -= ({id}); if (!sizeof (open_files[file])) m_delete (open_files, file); m_delete (open_files, id); } } array(string) file_open_places (string file) { file = combine_path (getcwd(), file); if (array(int) ids = open_files[file]) return map (ids, lambda (int id) { if (array ent = open_files[id]) return ent[1]; }) - ({0}); return 0; } void report_file_open_places (string file) { array(string) places = file_open_places (file); if (places) werror ("File " + file + " is currently opened from:\n" + map (places, lambda (string place) { return " * " +
8a531a2006-11-04Martin Nilsson  replace (place[..<1], "\n", "\n ");
ba6d7b2001-04-19Martin Stjernholm  }) * "\n\n" + "\n"); else
820f072002-03-25Martin Stjernholm  werror ("File " + file + " is currently not opened from any known place.\n");
ba6d7b2001-04-19Martin Stjernholm } #endif
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @decl string read_file(string filename) //! @decl string read_file(string filename, int start, int len) //!
8d03bf2004-09-01Martin Stjernholm //! Read @[len] lines from a regular file @[filename] after skipping //! @[start] lines and return those lines as a string. If both //! @[start] and @[len] are omitted the whole file is read. //! //! @throws //! Throws an error on any I/O error except when the file doesn't //! exist. //! //! @returns //! Returns @expr{0@} (zero) if the file doesn't exist or if //! @[start] is beyond the end of it. //! //! Returns a string with the requested data otherwise.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @seealso //! @[read_bytes()], @[write_file()] //!
00a65b2013-12-11Per Hedbor string(0..255) read_file(string filename,void|int start,void|int len)
c2a4061997-02-06Fredrik Hübinette (Hubbe) {
5a2a2c2000-09-10Per Hedbor  FILE f;
8d03bf2004-09-01Martin Stjernholm  string ret;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  f=FILE();
8d03bf2004-09-01Martin Stjernholm  if (!f->open(filename,"r")) { if (f->errno() == System.ENOENT) return 0; else
51f1ce2015-09-06Martin Nilsson  error ("Failed to open %O: %s.\n", filename, strerror (f->errno()));
8d03bf2004-09-01Martin Stjernholm  }
c2a4061997-02-06Fredrik Hübinette (Hubbe) 
af72c61998-01-17Henrik Grubbström (Grubba)  // Disallow devices and directories.
61a4242000-08-27Mirar (Pontus Hagland)  Stat st;
8d03bf2004-09-01Martin Stjernholm  if ((st = f->stat()) && !st->isreg) { error( "%O is not a regular file.\n", filename );
af72c61998-01-17Henrik Grubbström (Grubba)  }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  switch(query_num_arg()) { case 1:
64e6192003-06-27Martin Nilsson  ret=f->read();
8d03bf2004-09-01Martin Stjernholm  if (!ret)
51f1ce2015-09-06Martin Nilsson  error ("Failed to read %O: %s.\n", filename, strerror (f->errno()));
c2a4061997-02-06Fredrik Hübinette (Hubbe)  break; case 3:
029a022014-05-20Martin Nilsson  if( len==0 ) return ""; // Fallthrough case 2:
8d03bf2004-09-01Martin Stjernholm  while(start--) { if (!f->gets()) if (int err = f->errno())
51f1ce2015-09-06Martin Nilsson  error ("Failed to read %O: %s.\n", filename, strerror (err));
8d03bf2004-09-01Martin Stjernholm  else return ""; // EOF reached. }
029a022014-05-20Martin Nilsson  if( len==0 ) { ret=f->read(); break; }
15eff92002-10-12Martin Nilsson  String.Buffer buf=String.Buffer();
8d03bf2004-09-01Martin Stjernholm  while(len--)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
8d03bf2004-09-01Martin Stjernholm  if (string tmp = f->gets()) buf->add(tmp, "\n"); else if (int err = f->errno())
51f1ce2015-09-06Martin Nilsson  error ("Failed to read %O: %s.\n", filename, strerror (err));
8d03bf2004-09-01Martin Stjernholm  else break; // EOF reached.
c2a4061997-02-06Fredrik Hübinette (Hubbe)  }
15eff92002-10-12Martin Nilsson  ret=buf->get();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  destruct(buf); }
e0e7b52000-08-02Martin Stjernholm  f->close();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return ret; }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @decl string read_bytes(string filename, int start, int len) //! @decl string read_bytes(string filename, int start) //! @decl string read_bytes(string filename) //!
8d03bf2004-09-01Martin Stjernholm //! Read @[len] number of bytes from a regular file @[filename] //! starting at byte @[start], and return it as a string.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! If @[len] is omitted, the rest of the file will be returned. //! //! If @[start] is also omitted, the entire file will be returned. //!
3339642002-08-28Henrik Grubbström (Grubba) //! @throws
8d03bf2004-09-01Martin Stjernholm //! Throws an error on any I/O error except when the file doesn't //! exist.
3339642002-08-28Henrik Grubbström (Grubba) //! //! @returns
8d03bf2004-09-01Martin Stjernholm //! Returns @expr{0@} (zero) if the file doesn't exist or if //! @[start] is beyond the end of it.
3339642002-08-28Henrik Grubbström (Grubba) //! //! Returns a string with the requested data otherwise. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @seealso //! @[read_file], @[write_file()], @[append_file()] //!
00a65b2013-12-11Per Hedbor string(0..255) read_bytes(string filename, void|int start,void|int len)
c2a4061997-02-06Fredrik Hübinette (Hubbe) { string ret;
5a2a2c2000-09-10Per Hedbor  File f = File();
e965921997-07-02Henrik Grubbström (Grubba) 
8d03bf2004-09-01Martin Stjernholm  if (!f->open(filename,"r")) { if (f->errno() == System.ENOENT) return 0; else
51f1ce2015-09-06Martin Nilsson  error ("Failed to open %O: %s.\n", filename, strerror (f->errno()));
8d03bf2004-09-01Martin Stjernholm  }
af72c61998-01-17Henrik Grubbström (Grubba)  // Disallow devices and directories.
61a4242000-08-27Mirar (Pontus Hagland)  Stat st;
8d03bf2004-09-01Martin Stjernholm  if ((st = f->stat()) && !st->isreg) { error( "%O is not a regular file.\n", filename );
af72c61998-01-17Henrik Grubbström (Grubba)  }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  switch(query_num_arg()) { case 3:
029a022014-05-20Martin Nilsson  if( len==0 ) return ""; // Fallthrough case 2:
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  if(start)
8d03bf2004-09-01Martin Stjernholm  if (f->seek(start) < 0)
51f1ce2015-09-06Martin Nilsson  error ("Failed to seek in %O: %s.\n", filename, strerror(f->errno()));
c2a4061997-02-06Fredrik Hübinette (Hubbe)  }
029a022014-05-20Martin Nilsson  ret = len ? f->read(len) : f->read();
8d03bf2004-09-01Martin Stjernholm  if (!ret)
51f1ce2015-09-06Martin Nilsson  error ("Failed to read %O: %s.\n", filename, strerror (f->errno()));
e965921997-07-02Henrik Grubbström (Grubba)  f->close();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return ret; }
e803e62001-08-24Martin Stjernholm //! Write the string @[str] onto the file @[filename]. Any existing //! data in the file is overwritten.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
e912d42002-08-28Henrik Grubbström (Grubba) //! For a description of @[access], see @[Stdio.File()->open()]. //! //! @throws //! Throws an error if @[filename] couldn't be opened for writing. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @returns
8d03bf2004-09-01Martin Stjernholm //! Returns the number of bytes written, i.e. @expr{sizeof(str)@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @seealso
e912d42002-08-28Henrik Grubbström (Grubba) //! @[append_file()], @[read_bytes()], @[Stdio.File()->open()]
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! int write_file(string filename, string str, int|void access)
c2a4061997-02-06Fredrik Hübinette (Hubbe) { int ret;
5a2a2c2000-09-10Per Hedbor  File f = File();
e965921997-07-02Henrik Grubbström (Grubba) 
65340d2014-08-15Martin Nilsson  if (undefinedp (access))
334df51999-05-26Henrik Grubbström (Grubba)  access = 0666; if(!f->open(filename, "twc", access))
51f1ce2015-09-06Martin Nilsson  error("Couldn't open %O: %s.\n", filename, strerror(f->errno()));
8d03bf2004-09-01Martin Stjernholm 
ce918b2011-08-30Henrik Grubbström (Grubba)  while (ret < sizeof (str)) {
eec5ea2011-08-29Henrik Grubbström (Grubba)  int bytes = f->write(str[ret..]);
ce918b2011-08-30Henrik Grubbström (Grubba)  if (bytes <= 0) {
51f1ce2015-09-06Martin Nilsson  error ("Couldn't write to %O: %s.\n", filename, strerror (f->errno()));
eec5ea2011-08-29Henrik Grubbström (Grubba)  } ret += bytes;
ce918b2011-08-30Henrik Grubbström (Grubba)  }
8d03bf2004-09-01Martin Stjernholm 
e965921997-07-02Henrik Grubbström (Grubba)  f->close();
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return ret; }
e803e62001-08-24Martin Stjernholm //! Append the string @[str] onto the file @[filename]. //!
e912d42002-08-28Henrik Grubbström (Grubba) //! For a description of @[access], see @[Stdio.File->open()]. //! //! @throws //! Throws an error if @[filename] couldn't be opened for writing. //!
e803e62001-08-24Martin Stjernholm //! @returns
8d03bf2004-09-01Martin Stjernholm //! Returns the number of bytes written, i.e. @expr{sizeof(str)@}.
e803e62001-08-24Martin Stjernholm //! //! @seealso
e912d42002-08-28Henrik Grubbström (Grubba) //! @[write_file()], @[read_bytes()], @[Stdio.File()->open()]
e803e62001-08-24Martin Stjernholm //!
95ea182002-01-01Martin Nilsson int append_file(string filename, string str, int|void access)
070eeb1999-04-07Fredrik Hübinette (Hubbe) { int ret;
5a2a2c2000-09-10Per Hedbor  File f = File();
070eeb1999-04-07Fredrik Hübinette (Hubbe) 
65340d2014-08-15Martin Nilsson  if (undefinedp (access))
334df51999-05-26Henrik Grubbström (Grubba)  access = 0666; if(!f->open(filename, "awc", access))
51f1ce2015-09-06Martin Nilsson  error("Couldn't open %O: %s.\n", filename, strerror(f->errno()));
8d03bf2004-09-01Martin Stjernholm 
ce918b2011-08-30Henrik Grubbström (Grubba)  while (ret < sizeof (str)) {
eec5ea2011-08-29Henrik Grubbström (Grubba)  int bytes = f->write(str[ret..]);
ce918b2011-08-30Henrik Grubbström (Grubba)  if (bytes <= 0) {
51f1ce2015-09-06Martin Nilsson  error ("Couldn't write to %O: %s.\n", filename, strerror (f->errno()));
eec5ea2011-08-29Henrik Grubbström (Grubba)  } ret += bytes;
ce918b2011-08-30Henrik Grubbström (Grubba)  }
0c54572001-08-24Martin Stjernholm 
070eeb1999-04-07Fredrik Hübinette (Hubbe)  f->close(); return ret; }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Give the size of a file. Size -1 indicates that the file either //! does not exist, or that it is not readable by you. Size -2
d106052005-04-08Martin Nilsson //! indicates that it is a directory, -3 that it is a symlink and -4 //! that it is a device.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @seealso //! @[file_stat()], @[write_file()], @[read_bytes()] //! int file_size(string filename)
c2a4061997-02-06Fredrik Hübinette (Hubbe) {
61a4242000-08-27Mirar (Pontus Hagland)  Stat stat;
bbaf2b2000-12-12Henrik Grubbström (Grubba)  stat = file_stat(filename);
c2a4061997-02-06Fredrik Hübinette (Hubbe)  if(!stat) return -1;
fe7f542006-07-23Martin Stjernholm  // Please note that stat->size is not always the same thing as stat[1]. /mast return [int]stat[1];
c2a4061997-02-06Fredrik Hübinette (Hubbe) }
d87e1f2008-12-03Tor Edvardsson //! @decl string append_path(string absolute, string ... relative) //! @decl string append_path_unix(string absolute, string ... relative) //! @decl string append_path_nt(string absolute, string ... relative)
3524712015-05-26Martin Nilsson //!
d87e1f2008-12-03Tor Edvardsson //! Append @[relative] paths to an @[absolute] path and remove any //! @expr{"//"@}, @expr{"../"@} or @expr{"/."@} to produce a //! straightforward absolute path as a result.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
d87e1f2008-12-03Tor Edvardsson //! @expr{"../"@} is ignorded in the relative paths if it makes the //! created path begin with something else than the absolute path //! (or so far created path).
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
4ea09a2008-12-08Tor Edvardsson //! @[append_path_nt()] fixes drive letter issues in @[relative]
3524712015-05-26Martin Nilsson //! by removing the colon separator @expr{":"@} if it exists (k:/fnord appends
4ea09a2008-12-08Tor Edvardsson //! as k/fnord) //!
3524712015-05-26Martin Nilsson //! @[append_path_nt()] also makes sure that UNC path(s) in @[relative] is appended
4ea09a2008-12-08Tor Edvardsson //! correctly by removing any @expr{"\\"@} or @expr{"//"@} from the beginning. //!
d87e1f2008-12-03Tor Edvardsson //! @[append_path()] is equivalent to @[append_path_unix()] on UNIX-like //! operating systems, and equivalent to @[append_path_nt()] on NT-like //! operating systems.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
d87e1f2008-12-03Tor Edvardsson //! @seealso //! @[combine_path()]
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
d87e1f2008-12-03Tor Edvardsson  string append_path_unix(string absolute, string ... relative) {
4ea09a2008-12-08Tor Edvardsson  return combine_path_unix(absolute, @map(relative, lambda(string s) { return combine_path_unix("/", s)[1..]; }));
d87e1f2008-12-03Tor Edvardsson } string append_path_nt(string absolute, string ... relative)
23d0741999-11-23Fredrik Noring {
4ea09a2008-12-08Tor Edvardsson  return combine_path_nt(absolute, @map(relative, lambda(string s) { if(s[1..1] == ":") { s = s[0..0] + s[2..]; } else if(s[0..1] == "\\\\" || s[0..1] == "//") { s = s[2..]; } return combine_path_nt("/", s)[1..]; }));
23d0741999-11-23Fredrik Noring }
4ea09a2008-12-08Tor Edvardsson string append_path(string absolute, string ... relative) {
d87e1f2008-12-03Tor Edvardsson #ifdef __NT__
4ea09a2008-12-08Tor Edvardsson  return append_path_nt (absolute, @relative);
d87e1f2008-12-03Tor Edvardsson #else
4ea09a2008-12-08Tor Edvardsson  return append_path_unix (absolute, @relative);
d87e1f2008-12-03Tor Edvardsson #endif
4ea09a2008-12-08Tor Edvardsson }
d87e1f2008-12-03Tor Edvardsson 
8a1a772002-04-05Johan Sundström //! Returns a canonic representation of @[path] (without /./, /../, // //! and similar path segments). string simplify_path(string path) { if(has_prefix(path, "/")) return combine_path("/", path); return combine_path("/", path)[1..]; }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! This function prints a message to stderr along with a description //! of what went wrong if available. It uses the system errno to find //! out what went wrong, so it is only applicable to IO errors. //! //! @seealso //! @[werror()] //!
c2a4061997-02-06Fredrik Hübinette (Hubbe) void perror(string s) {
8490d22016-11-05Martin Nilsson  stderr->write("%s: %s.\n", s, strerror(errno()));
c2a4061997-02-06Fredrik Hübinette (Hubbe) }
5ae2381997-03-16Fredrik Hübinette (Hubbe) 
006aad1999-09-16Fredrik Noring /* * Predicates. */
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Check if a @[path] is a file. //! //! @returns
3fa5592013-06-20Martin Nilsson //! Returns true if the given path is a regular file, otherwise false.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @seealso //! @[exist()], @[is_dir()], @[is_link()], @[file_stat()] //!
006aad1999-09-16Fredrik Noring int is_file(string path) {
d106052005-04-08Martin Nilsson  if (Stat s = file_stat (path)) return [int]s->isreg;
6840b22000-12-01Martin Stjernholm  return 0;
006aad1999-09-16Fredrik Noring }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Check if a @[path] is a directory. //! //! @returns //! Returns true if the given path is a directory, otherwise false. //! //! @seealso //! @[exist()], @[is_file()], @[is_link()], @[file_stat()] //!
006aad1999-09-16Fredrik Noring int is_dir(string path) {
d106052005-04-08Martin Nilsson  if (Stat s = file_stat (path)) return [int]s->isdir;
6840b22000-12-01Martin Stjernholm  return 0;
006aad1999-09-16Fredrik Noring }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Check if a @[path] is a symbolic link. //! //! @returns //! Returns true if the given path is a symbolic link, otherwise false. //! //! @seealso //! @[exist()], @[is_dir()], @[is_file()], @[file_stat()] //!
006aad1999-09-16Fredrik Noring int is_link(string path) {
d106052005-04-08Martin Nilsson  if (Stat s = file_stat (path, 1)) return [int]s->islnk;
6840b22000-12-01Martin Stjernholm  return 0;
006aad1999-09-16Fredrik Noring }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Check if a @[path] exists. //! //! @returns //! Returns true if the given path exists (is a directory or file), //! otherwise false. //!
1d32fe2006-06-13Henrik Grubbström (Grubba) //! @note //! May fail with eg @[errno()] @tt{EFBIG@} if the file exists, //! but the filesystem doesn't support the file size. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @seealso //! @[is_dir()], @[is_file()], @[is_link()], @[file_stat()]
006aad1999-09-16Fredrik Noring int exist(string path) {
1d32fe2006-06-13Henrik Grubbström (Grubba)  return !!file_stat(path);
006aad1999-09-16Fredrik Noring }
99552b2004-09-03David Gourdelier //! Convert the mode_string string as returned by Stdio.Stat object //! to int suitable for chmod
3524712015-05-26Martin Nilsson //!
99552b2004-09-03David Gourdelier //! @param mode_string //! The string as return from Stdio.Stat()->mode_string //! @returns
3524712015-05-26Martin Nilsson //! An int matching the permission of the mode_string string suitable for
99552b2004-09-03David Gourdelier //! chmod int convert_modestring2int(string mode_string) { constant user_permissions_letters2value =
3524712015-05-26Martin Nilsson  ([
99552b2004-09-03David Gourdelier  "r": 0400, "w": 0200, "x": 0100, "s": 4000, "S": 2000, "t": 1000 ]); constant group_permissions_letters2value = ([ "r": 0040, "w": 0020, "x": 0010, "s": 4000, "S": 2000, "t": 1000 ]); constant other_permissions_letters2value = ([ "r": 0004, "w": 0002, "x": 0001, "s": 4000, "S": 2000, "t": 1000 ]); int result = 0; array arr_mode = mode_string / ""; if(sizeof(mode_string) != 10) { throw(({ "Invalid mode_string", backtrace() })); } for(int i = 1; i < 4; i++) { result += user_permissions_letters2value[arr_mode[i]]; } for(int i = 4; i < 7; i++) { result += group_permissions_letters2value[arr_mode[i]]; } for(int i = 7; i < 10; i++) { result += other_permissions_letters2value[arr_mode[i]]; } return result; }
8d49101998-01-21Fredrik Hübinette (Hubbe) int cp(string from, string to)
81de3a2003-06-18Martin Nilsson //! Copies the file @[from] to the new position @[to]. If there is //! no system function for cp, a new file will be created and the
809a322009-12-03Martin Stjernholm //! old one copied manually in chunks of @[DATA_CHUNK_SIZE] bytes.
e0abd72014-06-03Henrik Grubbström (Grubba) //!
99552b2004-09-03David Gourdelier //! This function can also copy directories recursively.
e0abd72014-06-03Henrik Grubbström (Grubba) //!
99552b2004-09-03David Gourdelier //! @returns //! 0 on error, 1 on success
e0abd72014-06-03Henrik Grubbström (Grubba) //!
99552b2004-09-03David Gourdelier //! @note
e0abd72014-06-03Henrik Grubbström (Grubba) //! This function keeps file and directory mode bits, unlike in Pike //! 7.6 and earlier.
8d49101998-01-21Fredrik Hübinette (Hubbe) {
99552b2004-09-03David Gourdelier  Stat stat = file_stat(from, 1);
3524712015-05-26Martin Nilsson  if( !stat )
a171772005-02-02Per Hedbor  return 0;
ee0f722011-04-14Martin Stjernholm 
99552b2004-09-03David Gourdelier  if(stat->isdir) { // recursive copying of directories
e0abd72014-06-03Henrik Grubbström (Grubba)  if (has_prefix(combine_path(to, "./"), combine_path(from, "./"))) { // to is a subdirectory of from. // // This is NOT a good idea, as it often will trigger an infinite loop. return 0; }
99552b2004-09-03David Gourdelier  if(!mkdir(to)) return 0;
d106052005-04-08Martin Nilsson  array(string) sub_files = get_dir(from);
99552b2004-09-03David Gourdelier  foreach(sub_files, string sub_file) { if(!cp(combine_path(from, sub_file), combine_path(to, sub_file))) return 0; }
e0e7b52000-08-02Martin Stjernholm  }
99552b2004-09-03David Gourdelier  else
8d49101998-01-21Fredrik Hübinette (Hubbe)  {
1bee512011-04-14Martin Stjernholm #if constant(System.cp) if (!System.cp (from, to)) return 0; #else
99552b2004-09-03David Gourdelier  File f=File(), t; if(!f->open(from,"r")) return 0; function(int,int|void:string) r=f->read; t=File(); if(!t->open(to,"wct")) { f->close(); return 0; }
02413d2011-10-10Martin Stjernholm  string data;
99552b2004-09-03David Gourdelier  function(string:int) w=t->write; do {
809a322009-12-03Martin Stjernholm  data=r(DATA_CHUNK_SIZE);
99552b2004-09-03David Gourdelier  if(!data) return 0; if(w(data)!=sizeof(data)) return 0;
809a322009-12-03Martin Stjernholm  }while(sizeof(data) == DATA_CHUNK_SIZE);
3524712015-05-26Martin Nilsson 
99552b2004-09-03David Gourdelier  f->close(); t->close();
1bee512011-04-14Martin Stjernholm #endif
99552b2004-09-03David Gourdelier  }
ee0f722011-04-14Martin Stjernholm  chmod(to, convert_modestring2int([string]stat->mode_string)); return 1;
8d49101998-01-21Fredrik Hübinette (Hubbe) }
b44d6c1999-04-16Henrik Grubbström (Grubba) 
ef9af62002-03-05Martin Stjernholm int file_equal (string file_1, string file_2) //! Returns nonzero if the given paths are files with identical //! content, returns zero otherwise. Zero is also returned for any //! sort of I/O error. { File f1 = File(), f2 = File();
5141092002-03-05Per Hedbor  if( file_1 == file_2 ) return 1;
ef9af62002-03-05Martin Stjernholm  if (!f1->open (file_1, "r") || !f2->open (file_2, "r")) return 0;
5141092002-03-05Per Hedbor  // Some optimizations. Stat s1 = f1->stat(), s2 = f2->stat(); if( s1->size != s2->size ) return 0; // Detect sym- or hardlinks to the same file. if( (s1->dev == s2->dev) && (s1->ino == s2->ino) ) return 1;
3524712015-05-26Martin Nilsson 
ef9af62002-03-05Martin Stjernholm  function(int,int|void:string) f1_read = f1->read, f2_read = f2->read; string d1, d2; do {
809a322009-12-03Martin Stjernholm  d1 = f1_read (DATA_CHUNK_SIZE);
ef9af62002-03-05Martin Stjernholm  if (!d1) return 0;
809a322009-12-03Martin Stjernholm  d2 = f2_read (DATA_CHUNK_SIZE);
ef9af62002-03-05Martin Stjernholm  if (d1 != d2) return 0;
809a322009-12-03Martin Stjernholm  } while (sizeof (d1) == DATA_CHUNK_SIZE);
ef9af62002-03-05Martin Stjernholm  f1->close(); f2->close(); return 1; }
9eaf1d2008-06-28Martin Nilsson protected void call_cp_cb(int len,
a9a46b1999-10-14Henrik Grubbström (Grubba)  function(int, mixed ...:void) cb, mixed ... args) { // FIXME: Check that the lengths are the same?
94e6dc2002-03-12Henrik Grubbström (Grubba)  cb(1, @args);
a9a46b1999-10-14Henrik Grubbström (Grubba) }
94e6dc2002-03-12Henrik Grubbström (Grubba) //! Copy a file asynchronously. //! //! This function is similar to @[cp()], but works asynchronously. //! //! @param from //! Name of file to copy. //! //! @param to //! Name of file to create or replace with a copy of @[from]. //!
e705bb2003-07-23Henrik Grubbström (Grubba) //! @param callback
94e6dc2002-03-12Henrik Grubbström (Grubba) //! Function to be called on completion.
cbe8c92003-04-07Martin Nilsson //! The first argument will be @expr{1@} on success, and @expr{0@} (zero)
e705bb2003-07-23Henrik Grubbström (Grubba) //! otherwise. The rest of the arguments to @[callback] are passed
94e6dc2002-03-12Henrik Grubbström (Grubba) //! verbatim from @[args]. //! //! @param args //! Extra arguments to pass to @[callback]. //! //! @note //! For @[callback] to be called, the backend must be active (ie
e705bb2003-07-23Henrik Grubbström (Grubba) //! @[main()] must have returned @expr{-1@}, or @[Pike.DefaultBackend] //! get called in some other way). The actual copying may start //! before the backend has activated.
94e6dc2002-03-12Henrik Grubbström (Grubba) //! //! @bugs //! Currently the file sizes are not compared, so the destination file //! (@[to]) may be truncated. //! //! @seealso //! @[cp()], @[sendfile()]
a9a46b1999-10-14Henrik Grubbström (Grubba) void async_cp(string from, string to,
94e6dc2002-03-12Henrik Grubbström (Grubba)  function(int, mixed...:void) callback, mixed ... args)
a9a46b1999-10-14Henrik Grubbström (Grubba) {
d106052005-04-08Martin Nilsson  File from_file = File(); File to_file = File();
a9a46b1999-10-14Henrik Grubbström (Grubba)  if ((!(from_file->open(from, "r"))) || (!(to_file->open(to, "wct")))) {
94e6dc2002-03-12Henrik Grubbström (Grubba)  call_out(callback, 0, 0, @args);
a9a46b1999-10-14Henrik Grubbström (Grubba)  return; }
94e6dc2002-03-12Henrik Grubbström (Grubba)  sendfile(0, from_file, 0, -1, 0, to_file, call_cp_cb, callback, @args);
a9a46b1999-10-14Henrik Grubbström (Grubba) }
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! Creates zero or more directories to ensure that the given @[pathname] is //! a directory. //! //! If a @[mode] is given, it's used for the new directories after being &'ed //! with the current umask (on OS'es that support this). //! //! @returns
e705bb2003-07-23Henrik Grubbström (Grubba) //! Returns zero on failure and nonzero on success.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @seealso //! @[mkdir()] //! int mkdirhier (string pathname, void|int mode)
e1e7892000-01-12Martin Stjernholm {
65340d2014-08-15Martin Nilsson  if (undefinedp (mode)) mode = 0777; // &'ed with umask anyway.
bbaf2b2000-12-12Henrik Grubbström (Grubba)  if (!sizeof(pathname)) return 0;
3c4fdd2002-09-20Marcus Comstedt  string path = ""; #ifdef __NT__ pathname = replace(pathname, "\\", "/"); if (pathname[1..2] == ":/" && `<=("A", upper_case(pathname[..0]), "Z")) path = pathname[..2], pathname = pathname[3..]; #endif
8a9c942013-07-12Henrik Grubbström (Grubba)  array(string) segments = pathname/"/"; if (segments[0] == "") {
e1e7892000-01-12Martin Stjernholm  path += "/";
8a9c942013-07-12Henrik Grubbström (Grubba)  pathname = pathname[1..]; segments = segments[1..]; } // FIXME: An alternative could be a binary search, // but since it is usually only the last few // segments of the path that are missing, we // just do a linear search from the end. int i = sizeof(segments); while (i--) { if (file_stat(path + segments[..i]*"/")) break; } i++; while (i < sizeof(segments)) { if (!mkdir(path + segments[..i++] * "/", mode)) { if (errno() != System.EEXIST) return 0; }
e1e7892000-01-12Martin Stjernholm  }
8a9c942013-07-12Henrik Grubbström (Grubba)  return is_dir(path + pathname);
e1e7892000-01-12Martin Stjernholm }
99552b2004-09-03David Gourdelier //! Remove a file or a directory tree.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! @returns //! Returns 0 on failure, nonzero otherwise. //! //! @seealso //! @[rm] //!
e1e7892000-01-12Martin Stjernholm int recursive_rm (string path) {
61a4242000-08-27Mirar (Pontus Hagland)  Stat a = file_stat(path, 1);
5da0c62000-06-22Fredrik Noring  if(!a) return 0;
20b92a2004-09-01Martin Stjernholm  if(a->isdir)
47723c2000-03-27Henrik Grubbström (Grubba)  if (array(string) sub = get_dir (path)) foreach( sub, string name )
99552b2004-09-03David Gourdelier  recursive_rm (combine_path(path, name));
20b92a2004-09-01Martin Stjernholm  return rm (path);
e1e7892000-01-12Martin Stjernholm }
3524712015-05-26Martin Nilsson //! Copy a file or a directory tree by copying and then
2a5cff2011-04-14Martin Stjernholm //! removing. Mode bits are preserved in the copy.
99552b2004-09-03David Gourdelier //! It's not the fastest but works on every OS and //! works well across different file systems. //! //! @returns //! Returns 0 on failure, nonzero otherwise. //! //! @seealso //! @[recursive_rm] @[cp] //! int recursive_mv(string from, string to) { if(!cp(from, to)) return 0;
e0abd72014-06-03Henrik Grubbström (Grubba)  // NB: We rely on cp() above failing if to is a subdirectory of from.
99552b2004-09-03David Gourdelier  return recursive_rm(from); }
b44d6c1999-04-16Henrik Grubbström (Grubba) /* * Asynchronous sending of files. */ #define READER_RESTART 4 #define READER_HALT 32
adf5d41999-05-22Henrik Grubbström (Grubba) // FIXME: Support for timeouts?
9eaf1d2008-06-28Martin Nilsson protected class nb_sendfile
b44d6c1999-04-16Henrik Grubbström (Grubba) {
9eaf1d2008-06-28Martin Nilsson  protected File from; protected int len; protected array(string) trailers; protected File to; protected Pike.Backend backend; protected function(int, mixed ...:void) callback; protected array(mixed) args;
b44d6c1999-04-16Henrik Grubbström (Grubba)  // NOTE: Always modified from backend callbacks, so no need // for locking.
66fe2a2009-12-03Martin Stjernholm  // // The strings in to_write are always split up into DATA_CHUNK_SIZE // pieces to limit the size of the strings passed to to->write(). // That way repeated operations like str=str[x..] are avoided on // arbitrarily large strings.
9eaf1d2008-06-28Martin Nilsson  protected array(string) to_write = ({}); protected int sent;
b44d6c1999-04-16Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected int reader_awake; protected int writer_awake;
b44d6c1999-04-16Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected int blocking_to; protected int blocking_from;
4e1d571999-04-19Henrik Grubbström (Grubba) 
b44d6c1999-04-16Henrik Grubbström (Grubba)  /* Reader */
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf( int f )
5a2a2c2000-09-10Per Hedbor  { switch( f ) { case 't': return "Stdio.Sendfile"; case 'O':
83f53a2003-06-27Martin Nilsson  return sprintf( "%t()", this );
5a2a2c2000-09-10Per Hedbor  } }
9eaf1d2008-06-28Martin Nilsson  protected void reader_done()
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Reader done.");
edc8321999-05-01Henrik Grubbström (Grubba) 
dfd8262000-11-06Per Hedbor  from->set_blocking();
b44d6c1999-04-16Henrik Grubbström (Grubba)  from = 0; if (trailers) {
4e1d571999-04-19Henrik Grubbström (Grubba)  to_write += trailers;
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
cfc3d81999-04-19Henrik Grubbström (Grubba)  if (blocking_to) { while(sizeof(to_write)) { if (!do_write()) { // Connection closed or Disk full. writer_done(); return; } } if (!from) { writer_done(); return; } } else { if (sizeof(to_write)) { start_writer();
dd02231999-05-21Henrik Grubbström (Grubba)  } else { writer_done(); return;
cfc3d81999-04-19Henrik Grubbström (Grubba)  }
b44d6c1999-04-16Henrik Grubbström (Grubba)  } }
9eaf1d2008-06-28Martin Nilsson  protected void close_cb(mixed ignored)
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Input EOF.");
b44d6c1999-04-16Henrik Grubbström (Grubba)  reader_done(); }
9eaf1d2008-06-28Martin Nilsson  protected void do_read()
4e1d571999-04-19Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking read.");
dfd8262000-11-06Per Hedbor  if( sizeof( to_write ) > 2) return;
da20102011-12-13Henrik Grubbström (Grubba)  string more_data = ""; if ((len < 0) || (len > DATA_CHUNK_SIZE)) { more_data = from->read(DATA_CHUNK_SIZE, 1); } else if (len) { more_data = from->read(len, 1); }
9ef2e82003-12-08Henrik Grubbström (Grubba)  if (!more_data) { SF_WERR(sprintf("Blocking read failed with errno: %d\n", from->errno())); more_data = ""; }
4e1d571999-04-19Henrik Grubbström (Grubba)  if (more_data == "") { // EOF.
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking read got EOF.");
edc8321999-05-01Henrik Grubbström (Grubba) 
4e1d571999-04-19Henrik Grubbström (Grubba)  from = 0; if (trailers) { to_write += (trailers - ({ "" })); trailers = 0; } } else {
da20102011-12-13Henrik Grubbström (Grubba)  if (len > 0) len -= sizeof(more_data);
4e1d571999-04-19Henrik Grubbström (Grubba)  to_write += ({ more_data }); } }
9eaf1d2008-06-28Martin Nilsson  protected void read_cb(mixed ignored, string data)
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Read callback.");
da20102011-12-13Henrik Grubbström (Grubba)  if (len >= 0) {
b44d6c1999-04-16Henrik Grubbström (Grubba)  if (sizeof(data) < len) { len -= sizeof(data);
66fe2a2009-12-03Martin Stjernholm  to_write += data / (float) DATA_CHUNK_SIZE;
b44d6c1999-04-16Henrik Grubbström (Grubba)  } else {
66fe2a2009-12-03Martin Stjernholm  to_write += data[..len-1] / (float) DATA_CHUNK_SIZE;
da20102011-12-13Henrik Grubbström (Grubba)  len = 0;
dfd8262000-11-06Per Hedbor  from->set_blocking();
b44d6c1999-04-16Henrik Grubbström (Grubba)  reader_done();
cfc3d81999-04-19Henrik Grubbström (Grubba)  return;
b44d6c1999-04-16Henrik Grubbström (Grubba)  } } else {
66fe2a2009-12-03Martin Stjernholm  to_write += data / (float) DATA_CHUNK_SIZE;
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
4e1d571999-04-19Henrik Grubbström (Grubba)  if (blocking_to) { while(sizeof(to_write)) { if (!do_write()) { // Connection closed or Disk full. writer_done(); return; } } if (!from) { writer_done(); return; } } else { if (sizeof(to_write) > READER_HALT) { // Go to sleep.
dfd8262000-11-06Per Hedbor  from->set_blocking();
4e1d571999-04-19Henrik Grubbström (Grubba)  reader_awake = 0; } start_writer();
b44d6c1999-04-16Henrik Grubbström (Grubba)  } }
9eaf1d2008-06-28Martin Nilsson  protected void start_reader()
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Starting the reader.");
b44d6c1999-04-16Henrik Grubbström (Grubba)  if (!reader_awake) { reader_awake = 1;
9ef2e82003-12-08Henrik Grubbström (Grubba)  from->set_nonblocking(read_cb, from->query_write_callback(), close_cb);
b44d6c1999-04-16Henrik Grubbström (Grubba)  } } /* Writer */
9eaf1d2008-06-28Martin Nilsson  protected void writer_done()
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Writer done.");
edc8321999-05-01Henrik Grubbström (Grubba) 
b44d6c1999-04-16Henrik Grubbström (Grubba)  // Disable any reader.
9f3f0c2015-02-19Henrik Grubbström (Grubba)  if (from && !blocking_from && from->set_nonblocking) {
9ef2e82003-12-08Henrik Grubbström (Grubba)  from->set_nonblocking(0, from->query_write_callback(), 0);
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
cfc3d81999-04-19Henrik Grubbström (Grubba)  // Disable any writer.
9f3f0c2015-02-19Henrik Grubbström (Grubba)  if (to && !blocking_to && to->set_nonblocking) {
9ef2e82003-12-08Henrik Grubbström (Grubba)  to->set_nonblocking(to->query_read_callback(), 0, to->query_close_callback());
cfc3d81999-04-19Henrik Grubbström (Grubba)  }
b44d6c1999-04-16Henrik Grubbström (Grubba)  // Make sure we get rid of any references... to_write = 0; trailers = 0; from = 0; to = 0;
f4050b2007-05-26Henrik Grubbström (Grubba)  backend = 0;
b44d6c1999-04-16Henrik Grubbström (Grubba)  array(mixed) a = args; function(int, mixed ...:void) cb = callback; args = 0; callback = 0;
ff70581999-04-19Henrik Grubbström (Grubba)  if (cb) { cb(sent, @a); }
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
9eaf1d2008-06-28Martin Nilsson  protected int do_write()
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking writer.");
edc8321999-05-01Henrik Grubbström (Grubba) 
26bcc52001-12-07Henrik Grubbström (Grubba)  int bytes = sizeof(to_write) && to->write(to_write);
b44d6c1999-04-16Henrik Grubbström (Grubba) 
c391c42000-01-07Henrik Grubbström (Grubba)  if (bytes >= 0) {
9ef2e82003-12-08Henrik Grubbström (Grubba)  SF_WERR(sprintf("Wrote %d bytes.", bytes));
b44d6c1999-04-16Henrik Grubbström (Grubba)  sent += bytes; int n; for (n = 0; n < sizeof(to_write); n++) { if (bytes < sizeof(to_write[n])) { to_write[n] = to_write[n][bytes..]; to_write = to_write[n..];
4e1d571999-04-19Henrik Grubbström (Grubba)  return 1;
b44d6c1999-04-16Henrik Grubbström (Grubba)  } else { bytes -= sizeof(to_write[n]); if (!bytes) { to_write = to_write[n+1..];
4e1d571999-04-19Henrik Grubbström (Grubba)  return 1; } } }
26bcc52001-12-07Henrik Grubbström (Grubba) 
4e1d571999-04-19Henrik Grubbström (Grubba)  return 1; } else {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking writer got EOF.");
4e1d571999-04-19Henrik Grubbström (Grubba)  // Premature end of file! return 0; } }
9eaf1d2008-06-28Martin Nilsson  protected void write_cb(mixed ignored)
4e1d571999-04-19Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Write callback.");
4e1d571999-04-19Henrik Grubbström (Grubba)  if (do_write()) { if (from) {
ff70581999-04-19Henrik Grubbström (Grubba)  if (sizeof(to_write) < READER_RESTART) { if (blocking_from) { do_read(); if (!sizeof(to_write)) { // Done. writer_done(); } } else {
4e1d571999-04-19Henrik Grubbström (Grubba)  if (!sizeof(to_write)) { // Go to sleep.
9ef2e82003-12-08Henrik Grubbström (Grubba)  to->set_nonblocking(to->query_read_callback(),0, to->query_close_callback());
4e1d571999-04-19Henrik Grubbström (Grubba)  writer_awake = 0;
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
4e1d571999-04-19Henrik Grubbström (Grubba)  start_reader();
b44d6c1999-04-16Henrik Grubbström (Grubba)  } }
4e1d571999-04-19Henrik Grubbström (Grubba)  } else if (!sizeof(to_write)) { // Done. writer_done();
b44d6c1999-04-16Henrik Grubbström (Grubba)  } } else { // Premature end of file! writer_done(); } }
9eaf1d2008-06-28Martin Nilsson  protected void start_writer()
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Starting the writer.");
edc8321999-05-01Henrik Grubbström (Grubba) 
b44d6c1999-04-16Henrik Grubbström (Grubba)  if (!writer_awake) { writer_awake = 1;
9ef2e82003-12-08Henrik Grubbström (Grubba)  to->set_nonblocking(to->query_read_callback(), write_cb,
fee52d2013-12-20Jonas Walldén  to->query_close_callback());
b44d6c1999-04-16Henrik Grubbström (Grubba)  } }
4e1d571999-04-19Henrik Grubbström (Grubba)  /* Blocking */
9eaf1d2008-06-28Martin Nilsson  protected void do_blocking()
4e1d571999-04-19Henrik Grubbström (Grubba)  {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking I/O.");
edc8321999-05-01Henrik Grubbström (Grubba) 
4e1d571999-04-19Henrik Grubbström (Grubba)  if (from && (sizeof(to_write) < READER_RESTART)) { do_read(); } if (sizeof(to_write) && do_write()) {
f4050b2007-05-26Henrik Grubbström (Grubba)  backend->call_out(do_blocking, 0);
4e1d571999-04-19Henrik Grubbström (Grubba)  } else {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking I/O done.");
ff70581999-04-19Henrik Grubbström (Grubba)  // Done.
4e1d571999-04-19Henrik Grubbström (Grubba)  from = 0;
cfc3d81999-04-19Henrik Grubbström (Grubba)  to = 0;
f4050b2007-05-26Henrik Grubbström (Grubba)  backend = 0;
4e1d571999-04-19Henrik Grubbström (Grubba)  writer_done(); } }
a4227d1999-08-08Henrik Grubbström (Grubba) #ifdef SENDFILE_DEBUG
c071bc2017-11-05Henrik Grubbström (Grubba)  protected void _destruct()
a4227d1999-08-08Henrik Grubbström (Grubba)  { werror("Stdio.sendfile(): Destructed.\n"); } #endif /* SENDFILE_DEBUG */
b44d6c1999-04-16Henrik Grubbström (Grubba)  /* Starter */
9eaf1d2008-06-28Martin Nilsson  protected void create(array(string) hd,
9026ad2003-12-15Henrik Grubbström (Grubba)  File f, int off, int l, array(string) tr, File t, function(int, mixed ...:void)|void cb, mixed ... a)
b44d6c1999-04-16Henrik Grubbström (Grubba)  {
84baee2014-08-11Henrik Grubbström (Grubba)  backend = (t->query_backend && t->query_backend()) || Pike.DefaultBackend; if (!l || !f) {
b44d6c1999-04-16Henrik Grubbström (Grubba)  // No need for from. f = 0; // No need to differentiate between headers and trailers. if (tr) { if (hd) { hd += tr; } else { hd = tr; } tr = 0; } }
66fe2a2009-12-03Martin Stjernholm  if (hd) to_write = map (hd, lambda (string s) { return s / (float) DATA_CHUNK_SIZE; }) * ({}) - ({""}); else to_write = ({});
b44d6c1999-04-16Henrik Grubbström (Grubba)  from = f; len = l;
66fe2a2009-12-03Martin Stjernholm  if (tr) trailers = map (tr, lambda (string s) { return s / (float) DATA_CHUNK_SIZE; }) * ({}) - ({""}); else trailers = ({});
b44d6c1999-04-16Henrik Grubbström (Grubba)  to = t; callback = cb; args = a;
dfd8262000-11-06Per Hedbor  blocking_to = to->is_file || ((!to->set_nonblocking) || (to->mode && !(to->mode() & PROP_NONBLOCK)));
4e1d571999-04-19Henrik Grubbström (Grubba)  if (blocking_to && to->set_blocking) {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking to.");
4e1d571999-04-19Henrik Grubbström (Grubba)  to->set_blocking(); }
b44d6c1999-04-16Henrik Grubbström (Grubba)  if (from) {
dfd8262000-11-06Per Hedbor  blocking_from = from->is_file || ((!from->set_nonblocking) || (from->mode && !(from->mode() & PROP_NONBLOCK)));
3524712015-05-26Martin Nilsson 
b44d6c1999-04-16Henrik Grubbström (Grubba)  if (off >= 0) { from->seek(off); }
4e1d571999-04-19Henrik Grubbström (Grubba)  if (blocking_from) {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Blocking from.");
4e1d571999-04-19Henrik Grubbström (Grubba)  if (from->set_blocking) { from->set_blocking(); } } else {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Starting reader.");
4e1d571999-04-19Henrik Grubbström (Grubba)  start_reader(); }
b44d6c1999-04-16Henrik Grubbström (Grubba)  }
4e1d571999-04-19Henrik Grubbström (Grubba)  if (blocking_to) { if (!from || blocking_from) { // Can't use the reader to push data. // Could have a direct call to do_blocking here, // but then the callback would be called from the wrong context.
6aeeab2001-12-04Martin Nilsson  SF_WERR("Using fully blocking I/O.");
f4050b2007-05-26Henrik Grubbström (Grubba)  backend->call_out(do_blocking, 0);
4e1d571999-04-19Henrik Grubbström (Grubba)  } } else {
edc8321999-05-01Henrik Grubbström (Grubba)  if (blocking_from) {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Reading some data.");
edc8321999-05-01Henrik Grubbström (Grubba)  do_read(); }
0d7a822017-11-23Henrik Grubbström (Grubba)  if (!from || sizeof(to_write)) {
6aeeab2001-12-04Martin Nilsson  SF_WERR("Starting the writer.");
4e1d571999-04-19Henrik Grubbström (Grubba)  start_writer(); }
b44d6c1999-04-16Henrik Grubbström (Grubba)  } } }
7dc3162001-04-27Henrik Grubbström (Grubba) //! @decl object sendfile(array(string) headers, @ //! File from, int offset, int len, @ //! array(string) trailers, @
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! File to)
7dc3162001-04-27Henrik Grubbström (Grubba) //! @decl object sendfile(array(string) headers, @ //! File from, int offset, int len, @ //! array(string) trailers, @ //! File to, @ //! function(int, mixed ...:void) callback, @
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! mixed ... args) //! //! Sends @[headers] followed by @[len] bytes starting at @[offset] //! from the file @[from] followed by @[trailers] to the file @[to]. //! When completed @[callback] will be called with the total number of //! bytes sent as the first argument, followed by @[args]. //! //! Any of @[headers], @[from] and @[trailers] may be left out
cbe8c92003-04-07Martin Nilsson //! by setting them to @expr{0@}.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //!
cbe8c92003-04-07Martin Nilsson //! Setting @[offset] to @expr{-1@} means send from the current position in
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @[from]. //!
cbe8c92003-04-07Martin Nilsson //! Setting @[len] to @expr{-1@} means send until @[from]'s end of file is
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! reached. //! //! @note //! The sending is performed asynchronously, and may complete
f4050b2007-05-26Henrik Grubbström (Grubba) //! both before and after the function returns.
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! For @[callback] to be called, the backend must be active (ie
e705bb2003-07-23Henrik Grubbström (Grubba) //! @[main()] must have returned @expr{-1@}, or @[Pike.DefaultBackend] //! get called in some other way).
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! //! In some cases, the backend must also be active for any sending to //! be performed at all. //!
5618cf2007-12-20Henrik Grubbström (Grubba) //! In Pike 7.4.496, Pike 7.6.120 and Pike 7.7 and later the backend //! associated with @[to] will be used rather than the default backend. //! Note that you usually will want @[from] to have the same backend as @[to].
f4050b2007-05-26Henrik Grubbström (Grubba) //!
ee15042015-10-22Henrik Grubbström (Grubba) //! @note //! The low-level sending may be performed with blocking I/O calls, and //! thus trigger the process being killed with @tt{SIGPIPE@} when the //! peer closes the other end. Add a call to @[signal()] to avoid this. //!
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @bugs //! FIXME: Support for timeouts? //! //! @seealso //! @[Stdio.File->set_nonblocking()] //!
b44d6c1999-04-16Henrik Grubbström (Grubba) object sendfile(array(string) headers,
d106052005-04-08Martin Nilsson  File from, int offset, int len,
b44d6c1999-04-16Henrik Grubbström (Grubba)  array(string) trailers,
d106052005-04-08Martin Nilsson  File to,
b44d6c1999-04-16Henrik Grubbström (Grubba)  function(int, mixed ...:void)|void cb, mixed ... args) {
59db4f2013-06-11Martin Nilsson #if !defined(DISABLE_FILES_SENDFILE) && constant(_Stdio.sendfile)
2d1c2d1999-04-20Henrik Grubbström (Grubba)  // Try using files.sendfile().
3524712015-05-26Martin Nilsson 
b44d6c1999-04-16Henrik Grubbström (Grubba)  mixed err = catch {
59db4f2013-06-11Martin Nilsson  return _Stdio.sendfile(headers, from, offset, len, trailers, to, cb, @args);
b44d6c1999-04-16Henrik Grubbström (Grubba)  }; #ifdef SENDFILE_DEBUG
08040d2008-12-17Jonas Wallden  werror("files.sendfile() failed:\n%s\n", describe_backtrace(err));
b44d6c1999-04-16Henrik Grubbström (Grubba) #endif /* SENDFILE_DEBUG */
9ef2e82003-12-08Henrik Grubbström (Grubba) #endif /* !DISABLE_FILES_SENDFILE && files.sendfile */
b44d6c1999-04-16Henrik Grubbström (Grubba)  // Use nb_sendfile instead. return nb_sendfile(headers, from, offset, len, trailers, to, cb, @args); }
485b701999-07-15Mirar (Pontus Hagland) 
7dc3162001-04-27Henrik Grubbström (Grubba) //! UDP (User Datagram Protocol) handling.
485b701999-07-15Mirar (Pontus Hagland) class UDP {
59db4f2013-06-11Martin Nilsson  inherit _Stdio.UDP;
bbaf2b2000-12-12Henrik Grubbström (Grubba) 
9aee552009-04-25Martin Stjernholm  private array extra=0; private function(mapping,mixed...:void) callback=0;
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! @decl UDP set_nonblocking()
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl UDP set_nonblocking(function(mapping(string:int|string), @ //! mixed ...:void) read_cb, @
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! mixed ... extra_args) //! //! Set this object to nonblocking mode. //! //! If @[read_cb] and @[extra_args] are specified, they will be passed on //! to @[set_read_callback()]. //! //! @returns //! The called object. //!
d106052005-04-08Martin Nilsson  this_program set_nonblocking(void|function(mapping,mixed...:void) f, mixed ... stuff)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  {
d106052005-04-08Martin Nilsson  if(f) set_read_callback(f,@stuff);
bbaf2b2000-12-12Henrik Grubbström (Grubba)  return _set_nonblocking(); }
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl UDP set_read_callback(function(mapping(string:int|string), @ //! mixed...) read_cb, @
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! mixed ... extra_args); //! //! The @[read_cb] function will receive a mapping similar to the mapping //! returned by @[read()]: //! @mapping
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @member string "data"
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Received data.
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @member string "ip"
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Data was sent from this IP.
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @member int "port"
bbaf2b2000-12-12Henrik Grubbström (Grubba)  //! Data was sent from this port. //! @endmapping //! //! @returns //! The called object. //! //! @seealso //! @[read()] //!
d106052005-04-08Martin Nilsson  this_program set_read_callback(function(mapping,mixed ...:void) f, mixed ...ext)
bbaf2b2000-12-12Henrik Grubbström (Grubba)  { extra=ext;
ae545e2003-07-30Martin Stjernholm  _set_read_callback((callback = f) && _read_callback);
83f53a2003-06-27Martin Nilsson  return this;
bbaf2b2000-12-12Henrik Grubbström (Grubba)  }
3524712015-05-26Martin Nilsson 
9aee552009-04-25Martin Stjernholm  private void _read_callback()
bbaf2b2000-12-12Henrik Grubbström (Grubba)  { mapping i; if (i=read()) callback(i,@extra); }
485b701999-07-15Mirar (Pontus Hagland) }
654f6f1999-10-04Fredrik Hübinette (Hubbe) 
bbaf2b2000-12-12Henrik Grubbström (Grubba) //! @decl void werror(string s) //! //! Write a message to stderr. Stderr is normally the console, even if //! the process output has been redirected to a file or pipe. //!
e705bb2003-07-23Henrik Grubbström (Grubba) //! @note //! This function is identical to @[predef::werror()]. //! //! @seealso //! @[predef::werror()]
7dc3162001-04-27Henrik Grubbström (Grubba) 
654f6f1999-10-04Fredrik Hübinette (Hubbe) constant werror=predef::werror;