~frankencode/drycore/trunk

« back to all changes in this revision

Viewing changes to dry/SystemStream.cpp

  • Committer: Frank Mertens
  • Date: 2013-02-27 18:43:50 UTC
  • Revision ID: frank@cyblogic.de-20130227184350-ypu14rj5e2r8gwqz
Initial commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 /*
 
2
  * Copyright (C) 2007-2013 Frank Mertens.
 
3
  *
 
4
  * This program is free software; you can redistribute it and/or
 
5
  * modify it under the terms of the GNU General Public License
 
6
  * as published by the Free Software Foundation; either version
 
7
  * 2 of the License, or (at your option) any later version.
 
8
  */
 
9
 
 
10
#include <sys/types.h>
 
11
#include <sys/uio.h> // readv
 
12
#include <errno.h>
 
13
#include <string.h>
 
14
#include <unistd.h> // read, write, select
 
15
#include <fcntl.h> // fcntl
 
16
#include <math.h> // modf
 
17
#include "SystemStream.hpp"
 
18
 
 
19
namespace dry
 
20
{
 
21
 
 
22
SystemStream::SystemStream(int fd)
 
23
        : fd_(fd),
 
24
          isattyCached_(false)
 
25
{}
 
26
 
 
27
SystemStream::~SystemStream()
 
28
{
 
29
        if (isOpen())
 
30
                if (fd_ >= 3) // because of StandardStreams concurrency
 
31
                        close();
 
32
}
 
33
 
 
34
int SystemStream::fd() const { return fd_; }
 
35
 
 
36
bool SystemStream::isTeletype() const
 
37
{
 
38
        if (!isattyCached_) {
 
39
                isatty_ = ::isatty(fd_);
 
40
                isattyCached_ = true;
 
41
        }
 
42
        return isatty_;
 
43
}
 
44
 
 
45
bool SystemStream::isOpen() const { return fd_ != -1; }
 
46
 
 
47
void SystemStream::close()
 
48
{
 
49
        if (::close(fd_) == -1)
 
50
                DRY_SYSTEM_EXCEPTION;
 
51
        fd_ = -1;
 
52
}
 
53
 
 
54
bool SystemStream::readyRead(double timeout)
 
55
{
 
56
        fd_set set;
 
57
        FD_ZERO(&set);
 
58
        FD_SET(fd_, &set);
 
59
        struct timeval tv;
 
60
        double sec = 0;
 
61
        tv.tv_usec = modf(timeout, &sec) * 1e6;
 
62
        tv.tv_sec = sec;
 
63
        int ret = ::select(fd_ + 1, &set, 0, 0, &tv);
 
64
        if (ret == -1)
 
65
                DRY_SYSTEM_EXCEPTION;
 
66
        return (ret > 0);
 
67
}
 
68
 
 
69
bool SystemStream::readyReadOrWrite(double timeout)
 
70
{
 
71
        fd_set rset, wset;
 
72
        FD_ZERO(&rset);
 
73
        FD_SET(fd_, &rset);
 
74
        wset = rset;
 
75
        struct timeval tv;
 
76
        double sec = 0;
 
77
        tv.tv_usec = modf(timeout, &sec) * 1e6;
 
78
        tv.tv_sec = sec;
 
79
        int ret = ::select(fd_ + 1, &rset, &wset, 0, &tv);
 
80
        if (ret == -1)
 
81
                DRY_SYSTEM_EXCEPTION;
 
82
        return (ret > 0);
 
83
}
 
84
 
 
85
int SystemStream::readAvail(void *buf, int bufSize)
 
86
{
 
87
        ssize_t ret = 0;
 
88
        while (true) {
 
89
                ret = ::read(fd_, buf, bufSize);
 
90
                if (ret == -1) {
 
91
                        if (errno == EINTR)
 
92
                                throw Interrupt();
 
93
                        if (errno == EWOULDBLOCK)
 
94
                                throw Timeout();
 
95
                        if (isTeletype()) { ret = 0; break; } // fancy HACK, needs review
 
96
                        DRY_SYSTEM_EXCEPTION;
 
97
                }
 
98
                break;
 
99
        }
 
100
        return ret;
 
101
}
 
102
 
 
103
void SystemStream::write(const void *buf, int bufFill)
 
104
{
 
105
        const uint8_t *buf2 = static_cast<const uint8_t*>(buf);
 
106
        while (bufFill > 0)
 
107
        {
 
108
                ssize_t ret = ::write(fd_, buf2, bufFill);
 
109
                if (ret == -1) {
 
110
                        if (errno == EINTR) throw Interrupt();
 
111
                        if (errno == EWOULDBLOCK) throw Timeout();
 
112
                        DRY_SYSTEM_EXCEPTION;
 
113
                }
 
114
                buf2 += ret;
 
115
                bufFill -= ret;
 
116
        }
 
117
}
 
118
 
 
119
void SystemStream::write(StringList *parts, const char *sep)
 
120
{
 
121
        int n = parts->length();
 
122
        int sepLen = str::len(sep);
 
123
        if (n <= 0) return;
 
124
        if (sepLen > 0) n += n - 1;
 
125
        struct iovec iov[n];
 
126
        for (int i = 0, j = 0; i < n; ++i) {
 
127
                if ((sepLen > 0) && ((i % 2) == 1)) {
 
128
                        iov[i].iov_base = const_cast<char*>(sep);
 
129
                        iov[i].iov_len = sepLen;
 
130
                }
 
131
                else {
 
132
                        ByteArray *part = parts->at(j++);
 
133
                        iov[i].iov_base = part->data();
 
134
                        iov[i].iov_len = part->size();
 
135
                }
 
136
        }
 
137
        ssize_t ret = ::writev(fd_, &iov[0], n);
 
138
        if (ret == -1) {
 
139
                if (errno == EINTR) throw Interrupt();
 
140
                if (errno == EWOULDBLOCK) throw Timeout();
 
141
                DRY_SYSTEM_EXCEPTION;
 
142
        }
 
143
}
 
144
 
 
145
void SystemStream::closeOnExec()
 
146
{
 
147
        if (::fcntl(fd_, F_SETFD, FD_CLOEXEC) == -1)
 
148
                DRY_SYSTEM_EXCEPTION;
 
149
}
 
150
 
 
151
} // namespace dry