#include #include #include #include #include #include "Handle.h" #include "config.h" Handle::Handle(const Handle & nh) : h(nh.h >= 0 ? dup(nh.h) : nh.h), closed(false), nonblock(false) { } Handle::~Handle() { close(); } Handle::Handle(int nh) : h(nh), closed(false) { } int Handle::GetHandle() { return h; } ssize_t Handle::write(const void *buf, size_t count) throw (GeneralException) { ssize_t r, tr = 0; bool done, full = false; do { done = true; errno = 0; if ((r = ::write(h, buf, count)) < 0) { if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { // Avant de déclarer une erreur, on vérifie si ce n'est pas un // problème lié au fait qu'il n'y a plus de place libre. Cela peut // arriver si l'on agit sur un pipe ou un handle. Nous // attendons encore une fois avant de déclarer l'erreur, // grace au drapeau full. if (full) { throw IOException(GetName(), IO_WRITE, count); } else { done = false; full = true; if (nonblock) { throw IOAgain(); } else { sleep(1); } } } else { throw IOException(GetName(), IO_WRITE, count); } } else if (r != count) { full = done = false; ((char *)buf) += r; tr += r; } } while (!done); return r + tr; } ssize_t Handle::read(void *buf, size_t count) throw (GeneralException) { ssize_t r; errno = 0; if ((r = ::read(h, buf, count)) < 0) { if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { // Avant de déclarer une erreur, on vérifie si ce n'est pas un // problème lié au fait qu'il n'y a plus d'octets. throw IOAgain(); } else { throw IOException(GetName(), IO_READ, count); } } if (!r) { close(); } return r; } bool Handle::IsClosed(void) { return closed; } bool Handle::IsNonBlock(void) { return nonblock; } void Handle::SetNonBlock(void) { if ((h >= 0) || !nonblock) { fcntl(h, F_SETFL, O_NONBLOCK); } nonblock = true; } Handle & operator<<(Handle & h, const String & s) { const char * p; p = s.to_charp(); h.write(p, strlen(p)); return h; } Handle & operator>>(Handle & h, String & s) { char t[BUFSIZ]; int i = 0, r; while ((r = h.read(&(t[i]), 1)) && (i != (BUFSIZ - 1))) { // Il y a souvent des \r\n dans les sockets par exemple, // ou bien en lisant des fichiers au format MS-DOS. On // ignore le \r pour ne garder que le \n, standard sous Unix. if (t[i] == '\r') { continue; } if (t[i] == '\n') { break; } else { i++; } } t[i] = '\0'; s = t; return h; } void Handle::close() { if (IsClosed()) { return; } if (h >= 0) { ::close(h); } h = -1; closed = 1; } bool Handle::CanRead(void) { return false; } bool Handle::CanWrite(void) { return false; } String Handle::GetName(void) { return _("Bare Handle - should not happend"); } off_t Handle::GetSize(void) { return -1; } time_t Handle::GetModif(void) { return -1; } bool Handle::CanWatch(void) { return true; }