1 #include "lib.h"
2
3 #include <sys/stat.h>
4 #include <limits.h>
5 #ifdef HAVE_DIRENT_H
6 #include <dirent.h>
7 #endif
8
ReadFile(FILE * fp)9 Str *ReadFile(FILE *fp) {
10 char buffer[65536];
11 if (fp == NULL)
12 return NULL;
13 StrArr *result = new StrArr();
14 for (;;) {
15 size_t nbytes = fread(buffer, 1, sizeof(buffer), fp);
16 if (nbytes == 0)
17 break;
18 result->add(new Str(buffer, nbytes));
19 }
20 return StrJoin(result, "");
21 }
22
ReadFile(const char * filename)23 Str *ReadFile(const char *filename) {
24 FILE *fp = fopen(filename, "r");
25 Str *result = ReadFile(fp);
26 fclose(fp);
27 return result;
28 }
29
ReadFile(Str * filename)30 Str *ReadFile(Str *filename) {
31 return ReadFile(filename->c_str());
32 }
33
WriteFile(FILE * fp,Str * data)34 int WriteFile(FILE *fp, Str *data) {
35 char *p = data->c_str();
36 Int len = data->len();
37 while (len != 0) {
38 Int written = fwrite(p, 1, len, fp);
39 if (written == 0)
40 return 0;
41 len -= written;
42 p += written;
43 }
44 return 1;
45 }
46
WriteFile(const char * filename,Str * data)47 int WriteFile(const char *filename, Str *data) {
48 FILE *fp = fopen(filename, "w");
49 if (!fp)
50 return 0;
51 int success = WriteFile(fp, data);
52 fclose(fp);
53 return success;
54 }
55
WriteFile(Str * filename,Str * data)56 int WriteFile(Str *filename, Str *data) {
57 return WriteFile(filename->c_str(), data);
58 }
59
ReadLines(const char * filename)60 StrArr *ReadLines(const char *filename) {
61 Str *contents = ReadFile(filename);
62 return contents->splitLines();
63 }
64
ReadLines(Str * filename)65 StrArr *ReadLines(Str *filename) {
66 return ReadLines(filename->c_str());
67 }
68
69 static char safe_chars[256];
70
InitSafeChars()71 void InitSafeChars() {
72 for (int i = 'a'; i <= 'z'; i++)
73 safe_chars[i] = 1;
74 for (int i = 'A'; i <= 'Z'; i++)
75 safe_chars[i] = 1;
76 for (int i = '0'; i <= '9'; i++)
77 safe_chars[i] = 1;
78 const char *p = ",._+:@%/-";
79 while (*p)
80 safe_chars[(unsigned char) *p++] = 1;
81 }
82
83 INIT(_AdLibOS, InitSafeChars(););
84
ShellEscape(Str * arg)85 Str *ShellEscape(Str *arg) {
86 int safe = 1;
87 for (Int i = 0; i < arg->len(); i++) {
88 if (!safe_chars[arg->byte(i)]) {
89 safe = 0;
90 break;
91 }
92 }
93 if (safe)
94 return arg;
95 Str *result = new Str(arg->len());
96 result->add('\'');
97 for (Str::Each it(arg); it; ++it) {
98 if (*it == '\'')
99 result->add("'\\''");
100 else
101 result->add(*it);
102 }
103 result->add('\'');
104 return result;
105 }
106
BuildCommand(Str * prog,StrArr * args)107 Str *BuildCommand(Str *prog, StrArr *args) {
108 Str *command = new Str(1024);
109 command->add(ShellEscape(prog));
110 for (Int i = 0; i < args->len(); i++) {
111 command->add(' ')->add(ShellEscape(args->at(i)));
112 }
113 return command;
114 }
115
ReadProcess(Str * prog,StrArr * args)116 Str *ReadProcess(Str *prog, StrArr *args) {
117 Str *command = BuildCommand(prog, args);
118 FILE *pipe = popen(command->c_str(), "r");
119 if (!pipe)
120 return NULL;
121 Str *result = ReadFile(pipe);
122 if (pclose(pipe))
123 return NULL;
124 return result;
125 }
126
ReadProcessLines(Str * prog,StrArr * args)127 StrArr *ReadProcessLines(Str *prog, StrArr *args) {
128 Str *output = ReadProcess(prog, args);
129 return output->splitLines();
130 }
131
WriteProcess(Str * prog,StrArr * args,Str * data)132 int WriteProcess(Str *prog, StrArr *args, Str *data) {
133 Str *command = BuildCommand(prog, args);
134 FILE *pipe = popen(command->c_str(), "w");
135 if (!pipe)
136 return 0;
137 int success = WriteFile(pipe, data);
138 if (pclose(pipe))
139 return 0;
140 return success;
141 }
142
System(Str * prog,StrArr * args)143 int System(Str *prog, StrArr *args) {
144 Str *command = BuildCommand(prog, args);
145 int result = system(command->c_str());
146 if (result >= 256)
147 result >>= 8;
148 return result;
149 }
150
Print(Str * str)151 void Print(Str *str) {
152 printf("%s", str->c_str());
153 }
154
PrintLn(Str * str)155 void PrintLn(Str *str) {
156 printf("%s\n", str->c_str());
157 }
158
PrintErr(Str * str)159 void PrintErr(Str *str) {
160 fprintf(stderr, "%s", str->c_str());
161 }
162
PrintErrLn(Str * str)163 void PrintErrLn(Str *str) {
164 fprintf(stderr, "%s\n", str->c_str());
165 }
166
Print(const char * str)167 void Print(const char *str) {
168 printf("%s", str);
169 }
170
PrintLn(const char * str)171 void PrintLn(const char *str) {
172 printf("%s\n", str);
173 }
174
PrintErr(const char * str)175 void PrintErr(const char *str) {
176 fprintf(stderr, "%s", str);
177 }
178
PrintErrLn(const char * str)179 void PrintErrLn(const char *str) {
180 fprintf(stderr, "%s\n", str);
181 }
182
Print(Int i)183 void Print(Int i) {
184 printf("%" WORD_FMT "d", i);
185 }
186
PrintLn(Int i)187 void PrintLn(Int i) {
188 printf("%" WORD_FMT "d\n", i);
189 }
190
PrintErr(Int i)191 void PrintErr(Int i) {
192 fprintf(stderr, "%" WORD_FMT "d", i);
193 }
194
PrintErrLn(Int i)195 void PrintErrLn(Int i) {
196 fprintf(stderr, "%" WORD_FMT "d\n", i);
197 }
198
CurrentDir()199 Str *CurrentDir() {
200 #ifdef PATH_MAX
201 char *path = getcwd(NULL, PATH_MAX);
202 #else
203 char *path = getcwd(NULL, 8192);
204 #endif
205 Str *result = new Str(path);
206 free(path);
207 return result;
208 }
209
ChDir(const char * path)210 bool ChDir(const char *path) {
211 return !chdir(path);
212 }
213
ChDir(Str * path)214 bool ChDir(Str *path) {
215 return ChDir(path->c_str());
216 }
217
FileStat(FileInfo & info,const char * path,bool follow_links)218 bool FileStat(FileInfo &info, const char *path, bool follow_links) {
219 struct stat st;
220 if (follow_links) {
221 if (stat(path, &st) < 0)
222 return false;
223 } else {
224 if (lstat(path, &st) < 0)
225 return false;
226 }
227 memset(&info, 0, sizeof(info));
228 if (S_ISDIR(st.st_mode)) {
229 info.is_dir = true;
230 } else if (S_ISREG(st.st_mode)) {
231 info.is_file = true;
232 } else if (S_ISLNK(st.st_mode)) {
233 info.is_link = true;
234 } else {
235 info.is_other = true;
236 }
237 info.atime = st.st_atime;
238 info.mtime = st.st_mtime;
239 info.ctime = st.st_ctime;
240 info.size = st.st_size;
241 return true;
242 }
243
FileStat(FileInfo & info,Str * path,bool follow_links)244 bool FileStat(FileInfo &info, Str *path, bool follow_links) {
245 return FileStat(info, path->c_str(), follow_links);
246 }
247
FileStat(const char * path,bool follow_links)248 FileInfo *FileStat(const char *path, bool follow_links) {
249 FileInfo info;
250 if (FileStat(info, path, follow_links))
251 return new FileInfo(info);
252 else
253 return NULL;
254 }
255
FileStat(Str * path,bool follow_links)256 FileInfo *FileStat(Str *path, bool follow_links) {
257 return FileStat(path->c_str(), follow_links);
258 }
259
ListFiles(const char * path)260 StrArr *ListFiles(const char *path) {
261 #ifdef HAVE_DIRENT_H
262 StrArr *result = new StrArr();
263 DIR *dir = opendir(path);
264 if (!dir)
265 return NULL;
266 for (;;) {
267 struct dirent *entry = readdir(dir);
268 if (!entry)
269 break;
270 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
271 continue;
272 result->add(new Str(entry->d_name));
273 }
274 closedir(dir);
275 return result;
276 #else
277 return NULL;
278 #endif
279 }
280
ListFiles(Str * path)281 StrArr *ListFiles(Str *path) {
282 return ListFiles(path->c_str());
283 }
284
WalkDir(StrArr * acc,const char * path,int mode)285 static void WalkDir(StrArr *acc, const char *path, int mode) {
286 StrArr *files = ListFiles(path);
287 if (!files)
288 return;
289 FileInfo info;
290 for (Int i = 0; i < files->len(); i++) {
291 Str *newpath = new Str(path);
292 if (!newpath->ends_with(PathSeparator))
293 newpath->add(PathSeparator);
294 newpath->add(files->at(i));
295 if (FileStat(info, newpath)) {
296 if (info.is_dir) {
297 newpath->add(PathSeparator);
298 WalkDir(acc, newpath->c_str(), mode);
299 if (mode & ListFilesAndDirs)
300 acc->add(newpath);
301 } else {
302 acc->add(newpath);
303 }
304 }
305 }
306 }
307
ListFileTree(const char * path,int mode)308 StrArr *ListFileTree(const char *path, int mode) {
309 StrArr *result = new StrArr();
310 FileInfo info;
311 if (FileStat(info, path, true)) {
312 if (info.is_dir) {
313 Str *dir = new Str(path);
314 if (!dir->ends_with(PathSeparator))
315 dir->add(PathSeparator);
316 Int prefixlen = dir->len();
317 result->add(dir);
318 WalkDir(result, dir->c_str(), mode);
319 if (mode & ListFilesRelative) {
320 for (Int i = 0; i < result->len(); i++) {
321 result->at(i)->remove(0, prefixlen);
322 }
323 }
324 } else {
325 if ((mode & ListFilesRelative) == 0)
326 result->add(S(path));
327 }
328 }
329 return result;
330 }
331
ListFileTree(Str * path,int mode)332 StrArr *ListFileTree(Str *path, int mode) {
333 return ListFileTree(path->c_str(), mode);
334 }
335
DirName(Str * path)336 Str *DirName(Str *path) {
337 Int pos = path->rfind(PathSeparator);
338 if (pos == NOWHERE) {
339 return path->clone();
340 } else {
341 return path->range_excl(0, pos);
342 }
343 }
344
BaseName(Str * path)345 Str *BaseName(Str *path) {
346 Int pos = path->rfind(PathSeparator);
347 if (pos == NOWHERE) {
348 return path->clone();
349 } else {
350 return path->range_excl(pos+1, path->len());
351 }
352 }
353
FileExtension(Str * path)354 Str *FileExtension(Str *path) {
355 Int slash = path->rfind(PathSeparator);
356 Int dot = path->rfind('.');
357 if (dot == NOWHERE || dot < slash) {
358 return S("");
359 } else {
360 return path->range_excl(dot, path->len());
361 }
362 }
363
364
MakeDirRec(Str * path)365 static bool MakeDirRec(Str *path) {
366 FileInfo info;
367 path = path->clone();
368 for (Int i = 1; i < path->len();) {
369 Int p = path->find(PathSeparator, i);
370 if (p == NOWHERE)
371 break;
372 path->at(p) = '\0';
373 if (FileStat(info, path, true)) {
374 if (!info.is_dir)
375 return false;
376 } else if (mkdir(path->c_str(), 0777) < 0) {
377 return false;
378 }
379 path->at(p) = PathSeparator[0];
380 i = p+1;
381 }
382 if (FileStat(info, path, true)) {
383 if (!info.is_dir)
384 return false;
385 } else if (mkdir(path->c_str(), 0777) < 0) {
386 return false;
387 }
388 return true;
389 }
390
AbsolutePath(Str * path)391 Str *AbsolutePath(Str *path) {
392 if (path->starts_with(PathSeparator)) {
393 return path->clone();
394 }
395 Str *result = CurrentDir();
396 return result->add(PathSeparator)->add(path);
397 }
398
NormalizePath(Str * path)399 Str *NormalizePath(Str *path) {
400 bool abs = path->starts_with(PathSeparator);
401 StrArr *parts = path->split(PathSeparator);
402 StrArr *result = new StrArr();
403 for (Int i = 0; i < parts->len(); i++) {
404 Str *part = parts->at(i);
405 if (part->eq("") || part->eq(".")) {
406 // do nothing
407 } else if (part->eq("..")) {
408 if (result->len() > 0)
409 result->pop();
410 else if (!abs)
411 result->add(part);
412 } else {
413 result->add(part);
414 }
415 }
416 if (abs)
417 return S(PathSeparator)->add(StrJoin(result, PathSeparator));
418 else
419 return StrJoin(result, PathSeparator);
420 }
421
GetEnv(const char * name)422 Str *GetEnv(const char *name) {
423 char *result = getenv(name);
424 if (result)
425 return new Str(result);
426 else
427 return NULL;
428 }
429
GetEnv(Str * name)430 Str *GetEnv(Str *name) {
431 return GetEnv(name->c_str());
432 }
433
ProgramPath()434 Str *ProgramPath() {
435 Str *arg0 = new Str(ArgV[0]);
436 Str *result = arg0;
437 if (arg0) {
438 if (FileStat(result, true)) {
439 return NormalizePath(AbsolutePath(result));
440 }
441 if (!arg0->starts_with(PathSeparator)) {
442 Str *path = GetEnv("PATH");
443 StrArr *paths = path ? path->split(':') : A();
444 for (Int i = 0; i < paths->len(); i++) {
445 Str *p = paths->at(i)->clone();
446 p->add(PathSeparator);
447 p->add(arg0);
448 if (FileStat(p, true)) {
449 result = p;
450 break;
451 }
452 }
453 }
454 }
455 return result ? NormalizePath(AbsolutePath(result)) : result;
456 }
457
MakeDir(const char * path,bool recursive)458 bool MakeDir(const char *path, bool recursive) {
459 if (!recursive)
460 return mkdir(path, 0777) >= 0;
461 return MakeDirRec(S(path));
462 }
463
MakeDir(Str * path,bool recursive)464 bool MakeDir(Str *path, bool recursive) {
465 if (!recursive)
466 return mkdir(path->c_str(), 0777) >= 0;
467 return MakeDirRec(path);
468 }
469
RemoveDir(const char * path)470 bool RemoveDir(const char *path) {
471 return rmdir(path) >= 0;
472 }
473
RemoveDir(Str * path)474 bool RemoveDir(Str *path) {
475 return RemoveDir(path->c_str());
476 }
477
RemoveFile(const char * path)478 bool RemoveFile(const char *path) {
479 return unlink(path) >= 0;
480 }
481
RemoveFile(Str * path)482 bool RemoveFile(Str *path) {
483 return RemoveFile(path->c_str());
484 }
485
486
Rename(const char * path,const char * path2)487 bool Rename(const char *path, const char *path2) {
488 return rename(path, path2) >= 0;
489 }
490
Rename(Str * path,Str * path2)491 bool Rename(Str *path, Str *path2) {
492 return Rename(path->c_str(), path2->c_str());
493 }
494