Root/src/utilities.cpp

1/***************************************************************************
2 * Copyright (C) 2006 by Massimiliano Torromeo *
3 * massimiliano.torromeo@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#include "utilities.h"
22
23#include "debug.h"
24
25#include <SDL.h>
26#include <algorithm>
27
28//for browsing the filesystem
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <fcntl.h>
32#include <dirent.h>
33#include <fstream>
34#include <iostream>
35#include <strings.h>
36#include <unistd.h>
37
38using namespace std;
39
40bool case_less::operator()(const string &left, const string &right) const {
41    return strcasecmp(left.c_str(), right.c_str()) < 0;
42}
43
44string trim(const string& s) {
45  auto b = s.find_first_not_of(" \t\r");
46  auto e = s.find_last_not_of(" \t\r");
47  return b == string::npos ? "" : string(s, b, e + 1 - b);
48}
49
50string ltrim(const string& s) {
51  auto b = s.find_first_not_of(" \t\r");
52  return b == string::npos ? "" : string(s, b);
53}
54
55string rtrim(const string& s) {
56  auto e = s.find_last_not_of(" \t\r");
57  return e == string::npos ? "" : string(s, 0, e + 1);
58}
59
60// See this article for a performance comparison of different approaches:
61// http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html
62string readFileAsString(string const& filename) {
63    ifstream in(filename, ios::in | ios::binary);
64    if (!in) {
65        return "<error opening " + string(filename) + ">";
66    }
67
68    // Get file size.
69    in.seekg(0, ios::end);
70    auto size = max(int(in.tellg()), 0); // tellg() returns -1 on errors
71    in.seekg(0, ios::beg);
72
73    string contents(size, '\0');
74    in.read(&contents[0], contents.size());
75    in.close();
76
77    if (in.fail()) {
78        return "<error reading " + string(filename) + ">";
79    } else {
80        contents.shrink_to_fit();
81        return contents;
82    }
83}
84
85constexpr int writeOpenFlags =
86#ifdef O_CLOEXEC
87        O_CLOEXEC | // Linux
88#endif
89        O_CREAT | O_WRONLY | O_TRUNC;
90
91// Use C functions since STL doesn't seem to have any way of applying fsync().
92bool writeStringToFile(string const& filename, string const& data) {
93    // Open temporary file.
94    string tempname = filename + '~';
95    int fd = open(tempname.c_str(), writeOpenFlags, S_IRUSR | S_IWUSR);
96    if (fd < 0) {
97        return false;
98    }
99
100    // Write temporary file.
101    const char *bytes = data.c_str();
102    size_t remaining = data.size();
103    bool ok = true;
104    while (remaining != 0) {
105        ssize_t written = write(fd, bytes, remaining);
106        if (written <= 0) {
107            ok = false;
108            break;
109        } else {
110            bytes += written;
111            remaining -= written;
112        }
113    }
114    if (ok) {
115        ok = fsync(fd) == 0;
116    }
117
118    // Close temporary file.
119    ok &= close(fd) == 0;
120
121    // Replace actual output file with temporary file.
122    if (ok) {
123        ok = rename(tempname.c_str(), filename.c_str()) == 0;
124    }
125
126    return ok;
127}
128
129constexpr int dirOpenFlags =
130#ifdef O_DIRECTORY
131        O_DIRECTORY | // Linux
132#endif
133#ifdef O_CLOEXEC
134        O_CLOEXEC | // Linux
135#endif
136        O_RDONLY;
137
138bool syncDir(string const& dirname)
139{
140    int fd = open(dirname.c_str(), dirOpenFlags);
141    if (fd < 0) {
142        return false;
143    }
144
145    bool ok = fsync(fd) == 0;
146
147    ok &= close(fd) == 0;
148
149    return ok;
150}
151
152string parentDir(string const& dir) {
153    // Note that size() is unsigned, so for short strings the '- 2' wraps
154    // around and as a result the entire string is searched, which is fine.
155    auto p = dir.rfind('/', dir.size() - 2);
156    return p == string::npos ? "/" : dir.substr(0, p + 1);
157}
158
159bool fileExists(const string &file) {
160    return access(file.c_str(), F_OK) == 0;
161}
162
163bool rmtree(string path) {
164    DIR *dirp;
165    struct stat st;
166    struct dirent *dptr;
167    string filepath;
168
169    DEBUG("RMTREE: '%s'\n", path.c_str());
170
171    if ((dirp = opendir(path.c_str())) == NULL) return false;
172    if (path[path.length()-1]!='/') path += "/";
173
174    while ((dptr = readdir(dirp))) {
175        filepath = dptr->d_name;
176        if (filepath=="." || filepath=="..") continue;
177        filepath = path+filepath;
178        int statRet = stat(filepath.c_str(), &st);
179        if (statRet == -1) continue;
180        if (S_ISDIR(st.st_mode)) {
181            if (!rmtree(filepath)) return false;
182        } else {
183            if (unlink(filepath.c_str())!=0) return false;
184        }
185    }
186
187    closedir(dirp);
188    return rmdir(path.c_str())==0;
189}
190
191int constrain(int x, int imin, int imax) {
192    return min(imax, max(imin, x));
193}
194
195//Configuration parsing utilities
196int evalIntConf (ConfIntHash& hash, const std::string &key, int def, int imin, int imax) {
197    auto it = hash.find(key);
198    if (it == hash.end()) {
199        return hash[key] = def;
200    } else {
201        return it->second = constrain(it->second, imin, imax);
202    }
203}
204
205bool split (vector<string> &vec, const string &str, const string &delim, bool destructive) {
206    vec.clear();
207
208    if (delim.empty()) {
209        vec.push_back(str);
210        return false;
211    }
212
213    std::string::size_type i = 0;
214    std::string::size_type j = 0;
215
216    while(1) {
217        j = str.find(delim,i);
218        if (j==std::string::npos) {
219            vec.push_back(str.substr(i));
220            break;
221        }
222
223        if (!destructive)
224            j += delim.size();
225
226        vec.push_back(str.substr(i,j-i));
227
228        if (destructive)
229            i = j + delim.size();
230
231        if (i==str.size()) {
232            vec.push_back(std::string());
233            break;
234        }
235    }
236
237    return true;
238}
239
240string strreplace (string orig, const string &search, const string &replace) {
241    string::size_type pos = orig.find( search, 0 );
242    while (pos != string::npos) {
243        orig.replace(pos,search.length(),replace);
244        pos = orig.find( search, pos+replace.length() );
245    }
246    return orig;
247}
248
249string cmdclean (string cmdline) {
250    string spchars = "\\`$();|{}&'\"*?<>[]!^~-#\n\r ";
251    for (uint i=0; i<spchars.length(); i++) {
252        string curchar = spchars.substr(i,1);
253        cmdline = strreplace(cmdline, curchar, "\\"+curchar);
254    }
255    return cmdline;
256}
257
258int intTransition(int from, int to, long tickStart, long duration, long tickNow) {
259    if (tickNow<0) tickNow = SDL_GetTicks();
260    return constrain(((tickNow-tickStart) * (to-from)) / duration, from, to);
261    // elapsed increments
262}
263
264void inject_user_event(enum EventCode code, void *data1, void *data2)
265{
266    SDL_UserEvent e = {
267        .type = SDL_USEREVENT,
268        .code = code,
269        .data1 = data1,
270        .data2 = data2,
271    };
272
273    /* Inject an user event, that will be handled as a "repaint"
274     * event by the InputManager */
275    SDL_PushEvent((SDL_Event *) &e);
276    DEBUG("Injecting event code %i\n", e.code);
277}
278

Archive Download this file



interactive