cpp

Coverage Report

Created: 2022-07-20 01:16

/home/uke/oil/cpp/leaky_core.cc
Line
Count
Source (jump to first uncovered line)
1
// leaky_core.cc
2
3
// clang-format off
4
#include "mycpp/myerror.h"
5
// clang-format on
6
7
#include "cpp/leaky_core.h"
8
9
#include <errno.h>
10
#include <pwd.h>  // passwd
11
#include <signal.h>
12
#include <sys/resource.h>  // getrusage
13
#include <sys/times.h>     // tms / times()
14
#include <sys/utsname.h>   // uname
15
#include <sys/wait.h>      // waitpid()
16
#include <time.h>          // time()
17
#include <unistd.h>        // getuid(), environ
18
19
#include "mycpp/mylib_leaky.h"
20
21
using mylib::CopyStr;
22
23
namespace pyos {
24
25
0
Tuple2<int, int> WaitPid() {
26
0
  int status;
27
0
  int result = ::waitpid(-1, &status, WUNTRACED);
28
0
  if (result < 0) {
29
0
    return Tuple2<int, int>(-1, errno);
30
0
  }
31
0
  return Tuple2<int, int>(result, status);
32
0
}
33
34
2
Tuple2<int, int> Read(int fd, int n, List<Str*>* chunks) {
35
  // TODO: Use garbage-collected APIs instead of malloc()
36
37
2
  char* buf = static_cast<char*>(malloc(n));
38
2
  int length = ::read(fd, buf, n);
39
2
  if (length < 0) {
40
0
    free(buf);
41
0
    return Tuple2<int, int>(-1, errno);
42
0
  }
43
2
  if (length == 0) {
44
1
    free(buf);
45
1
    return Tuple2<int, int>(length, 0);
46
1
  }
47
1
  Str* s = new Str(buf, length);
48
  // MYLIB_LEAKY: the buffer is now owned by the Str instance
49
  // free(buf);
50
1
  chunks->append(s);
51
1
  return Tuple2<int, int>(length, 0);
52
2
}
53
54
3
Tuple2<int, int> ReadByte(int fd) {
55
3
  unsigned char buf[1];
56
3
  ssize_t n = read(fd, &buf, 1);
57
3
  if (n < 0) {  // read error
58
0
    return Tuple2<int, int>(-1, errno);
59
3
  } else if (n == 0) {  // EOF
60
1
    return Tuple2<int, int>(EOF_SENTINEL, 0);
61
2
  } else {  // return character
62
2
    return Tuple2<int, int>(buf[0], 0);
63
2
  }
64
3
}
65
66
// for read --line
67
0
Str* ReadLine() {
68
0
  assert(0);  // Does this get called?
69
0
}
70
71
0
Dict<Str*, Str*>* Environ() {
72
0
  auto d = new Dict<Str*, Str*>();
73
74
0
  for (char** env = environ; *env; ++env) {
75
0
    char* pair = *env;
76
77
0
    char* eq = strchr(pair, '=');
78
0
    assert(eq != nullptr);  // must look like KEY=value
79
80
0
    int key_len = eq - pair;
81
0
    char* buf = static_cast<char*>(malloc(key_len + 1));
82
0
    memcpy(buf, pair, key_len);  // includes NUL terminator
83
0
    buf[key_len] = '\0';
84
85
0
    Str* key = CopyStr(buf, key_len);
86
87
0
    int len = strlen(pair);
88
0
    int val_len = len - key_len - 1;
89
0
    char* buf2 = static_cast<char*>(malloc(val_len + 1));
90
0
    memcpy(buf2, eq + 1, val_len);  // copy starting after =
91
0
    buf2[val_len] = '\0';
92
93
0
    Str* val = CopyStr(buf2, val_len);
94
95
0
    d->set(key, val);
96
0
  }
97
98
0
  return d;
99
0
}
100
101
0
int Chdir(Str* dest_dir) {
102
0
  mylib::Str0 d(dest_dir);
103
0
  if (chdir(d.Get()) == 0) {
104
0
    return 0;  // success
105
0
  } else {
106
0
    return errno;
107
0
  }
108
0
}
109
110
0
Str* GetMyHomeDir() {
111
0
  uid_t uid = getuid();  // always succeeds
112
113
  // Don't free this.  (May return a pointer to a static area)
114
0
  struct passwd* entry = getpwuid(uid);
115
0
  if (entry == nullptr) {
116
0
    return nullptr;
117
0
  }
118
0
  return CopyStr(entry->pw_dir);
119
0
}
120
121
0
Str* GetHomeDir(Str* user_name) {
122
0
  mylib::Str0 user_name0(user_name);
123
124
  // Don't free this.  (May return a pointer to a static area)
125
0
  struct passwd* entry = getpwnam(user_name0.Get());
126
0
  if (entry == nullptr) {
127
0
    return nullptr;
128
0
  }
129
0
  return CopyStr(entry->pw_dir);
130
0
}
131
132
0
Str* GetUserName(int uid) {
133
0
  Str* result = kEmptyString;
134
135
0
  if (passwd* pw = getpwuid(uid)) {
136
0
    result = new Str(pw->pw_name);
137
0
  } else {
138
0
    throw new IOError(errno);
139
0
  }
140
141
0
  return result;
142
0
}
143
144
0
Str* OsType() {
145
0
  Str* result = kEmptyString;
146
147
0
  utsname un = {};
148
0
  if (::uname(&un) == 0) {
149
0
    result = new Str(un.sysname);
150
0
  } else {
151
0
    throw new IOError(errno);
152
0
  }
153
154
0
  return result;
155
0
}
156
157
0
Tuple3<double, double, double> Time() {
158
0
  rusage ru;  // NOTE(Jesse): Doesn't have to be cleared to 0.  The kernel
159
              // clears unused fields.
160
0
  if (::getrusage(RUSAGE_SELF, &ru) == -1) {
161
0
    throw new IOError(errno);
162
0
  }
163
164
0
  time_t t = ::time(nullptr);
165
0
  auto result = Tuple3<double, double, double>(
166
0
      (double)t, (double)ru.ru_utime.tv_sec, (double)ru.ru_stime.tv_sec);
167
0
  return result;
168
0
}
169
170
0
void PrintTimes() {
171
0
  tms t;
172
0
  if (times(&t) == -1) {
173
0
    throw new IOError(errno);
174
0
  } else {
175
0
    {
176
0
      int user_minutes = t.tms_utime / 60;
177
0
      float user_seconds = t.tms_utime % 60;
178
0
      int system_minutes = t.tms_stime / 60;
179
0
      float system_seconds = t.tms_stime % 60;
180
0
      printf("%dm%1.3fs %dm%1.3fs", user_minutes, user_seconds, system_minutes,
181
0
             system_seconds);
182
0
    }
183
184
0
    {
185
0
      int child_user_minutes = t.tms_cutime / 60;
186
0
      float child_user_seconds = t.tms_cutime % 60;
187
0
      int child_system_minutes = t.tms_cstime / 60;
188
0
      float child_system_seconds = t.tms_cstime % 60;
189
0
      printf("%dm%1.3fs %dm%1.3fs", child_user_minutes, child_user_seconds,
190
0
             child_system_minutes, child_system_seconds);
191
0
    }
192
0
  }
193
0
}
194
195
0
bool InputAvailable(int fd) {
196
0
  NotImplemented();
197
0
}
198
199
0
void SignalState_AfterForkingChild() {
200
0
  signal(SIGQUIT, SIG_DFL);
201
0
  signal(SIGPIPE, SIG_DFL);
202
0
  signal(SIGTSTP, SIG_DFL);
203
0
}
204
205
}  // namespace pyos
206
207
namespace pyutil {
208
209
0
bool IsValidCharEscape(int c) {
210
0
  if (c == '/' || c == '.' || c == '-') {
211
0
    return false;
212
0
  }
213
0
  if (c == ' ') {  // foo\ bar is idiomatic
214
0
    return true;
215
0
  }
216
0
  return ispunct(c);
217
0
}
218
219
3
Str* ChArrayToString(List<int>* ch_array) {
220
3
  int n = len(ch_array);
221
3
  unsigned char* buf = static_cast<unsigned char*>(malloc(n + 1));
222
11
  for (int i = 0; i < n; ++i) {
223
8
    buf[i] = ch_array->index_(i);
224
8
  }
225
3
  buf[n] = '\0';
226
3
  return new Str(reinterpret_cast<char*>(buf), n);
227
3
}
228
229
0
Str* _ResourceLoader::Get(Str* path) {
230
0
  return new Str("TODO");
231
0
}
232
233
0
_ResourceLoader* GetResourceLoader() {
234
0
  return new _ResourceLoader();
235
0
}
236
237
0
void CopyFile(Str* in_path, Str* out_path) {
238
0
  assert(0);
239
0
}
240
241
0
Str* GetVersion(_ResourceLoader* loader) {
242
0
  return new Str("TODO");
243
0
}
244
245
0
Str* ShowAppVersion(Str* app_name, _ResourceLoader* loader) {
246
0
  assert(0);
247
0
}
248
249
2
Str* BackslashEscape(Str* s, Str* meta_chars) {
250
2
  int upper_bound = s->len_ * 2;
251
2
  char* buf = static_cast<char*>(malloc(upper_bound));
252
2
  char* p = buf;
253
254
11
  for (int i = 0; i < s->len_; ++i) {
255
9
    char c = s->data_[i];
256
9
    if (memchr(meta_chars->data_, c, meta_chars->len_)) {
257
3
      *p++ = '\\';
258
3
    }
259
9
    *p++ = c;
260
9
  }
261
2
  int len = p - buf;
262
2
  return new Str(buf, len);
263
2
}
264
265
// Hack so e->errno will work below
266
#undef errno
267
268
0
Str* strerror(_OSError* e) {
269
0
  return new Str(::strerror(e->errno));
270
0
}
271
272
}  // namespace pyutil