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 <sstream>
36#include <strings.h>
37#include <unistd.h>
38
39using namespace std;
40
41bool case_less::operator()(const string &left, const string &right) const {
42    return strcasecmp(left.c_str(), right.c_str()) < 0;
43}
44
45string trim(const string& s) {
46  auto b = s.find_first_not_of(" \t\r");
47  auto e = s.find_last_not_of(" \t\r");
48  return b == string::npos ? "" : string(s, b, e + 1 - b);
49}
50
51string ltrim(const string& s) {
52  auto b = s.find_first_not_of(" \t\r");
53  return b == string::npos ? "" : string(s, b);
54}
55
56string rtrim(const string& s) {
57  auto e = s.find_last_not_of(" \t\r");
58  return e == string::npos ? "" : string(s, 0, e + 1);
59}
60
61// See this article for a performance comparison of different approaches:
62// http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html
63string readFileAsString(string const& filename) {
64    ifstream in(filename, ios::in | ios::binary);
65    if (!in) {
66        return "<error opening " + string(filename) + ">";
67    }
68
69    // Get file size.
70    in.seekg(0, ios::end);
71    auto size = max(int(in.tellg()), 0); // tellg() returns -1 on errors
72    in.seekg(0, ios::beg);
73
74    string contents(size, '\0');
75    in.read(&contents[0], contents.size());
76    in.close();
77
78    if (in.fail()) {
79        return "<error reading " + string(filename) + ">";
80    } else {
81        contents.shrink_to_fit();
82        return contents;
83    }
84}
85
86constexpr int writeOpenFlags =
87#ifdef O_CLOEXEC
88        O_CLOEXEC | // Linux
89#endif
90        O_CREAT | O_WRONLY | O_TRUNC;
91
92// Use C functions since STL doesn't seem to have any way of applying fsync().
93bool writeStringToFile(string const& filename, string const& data) {
94    // Open temporary file.
95    string tempname = filename + '~';
96    int fd = open(tempname.c_str(), writeOpenFlags, S_IRUSR | S_IWUSR);
97    if (fd < 0) {
98        return false;
99    }
100
101    // Write temporary file.
102    const char *bytes = data.c_str();
103    size_t remaining = data.size();
104    bool ok = true;
105    while (remaining != 0) {
106        ssize_t written = write(fd, bytes, remaining);
107        if (written <= 0) {
108            ok = false;
109            break;
110        } else {
111            bytes += written;
112            remaining -= written;
113        }
114    }
115    if (ok) {
116        ok = fsync(fd) == 0;
117    }
118
119    // Close temporary file.
120    ok &= close(fd) == 0;
121
122    // Replace actual output file with temporary file.
123    if (ok) {
124        ok = rename(tempname.c_str(), filename.c_str()) == 0;
125    }
126
127    return ok;
128}
129
130constexpr int dirOpenFlags =
131#ifdef O_DIRECTORY
132        O_DIRECTORY | // Linux
133#endif
134#ifdef O_CLOEXEC
135        O_CLOEXEC | // Linux
136#endif
137        O_RDONLY;
138
139bool syncDir(string const& dirname)
140{
141    int fd = open(dirname.c_str(), dirOpenFlags);
142    if (fd < 0) {
143        return false;
144    }
145
146    bool ok = fsync(fd) == 0;
147
148    ok &= close(fd) == 0;
149
150    return ok;
151}
152
153string parentDir(string const& dir) {
154    // Note that size() is unsigned, so for short strings the '- 2' wraps
155    // around and as a result the entire string is searched, which is fine.
156    auto p = dir.rfind('/', dir.size() - 2);
157    return p == string::npos ? "/" : dir.substr(0, p + 1);
158}
159
160bool fileExists(const string &file) {
161    return access(file.c_str(), F_OK) == 0;
162}
163
164string uniquePath(string const& dir, string const& name)
165{
166    string path = dir + "/" + name;
167    unsigned int x = 2;
168    while (fileExists(path)) {
169        stringstream ss;
170        ss << dir << '/' << name << x;
171        ss >> path;
172        x++;
173    }
174    return path;
175}
176
177int constrain(int x, int imin, int imax) {
178    return min(imax, max(imin, x));
179}
180
181//Configuration parsing utilities
182int evalIntConf (ConfIntHash& hash, const std::string &key, int def, int imin, int imax) {
183    auto it = hash.find(key);
184    if (it == hash.end()) {
185        return hash[key] = def;
186    } else {
187        return it->second = constrain(it->second, imin, imax);
188    }
189}
190
191void split(vector<string>& vec, string const& str, string const& delim) {
192    vec.clear();
193
194    if (delim.empty()) {
195        vec.push_back(str);
196        return;
197    }
198
199    string::size_type i = 0, j;
200    while ((j = str.find(delim, i)) != string::npos) {
201        vec.push_back(str.substr(i, j - i));
202        i = j + delim.size();
203    }
204    vec.push_back(str.substr(i));
205}
206
207string strreplace (string orig, const string &search, const string &replace) {
208    string::size_type pos = orig.find( search, 0 );
209    while (pos != string::npos) {
210        orig.replace(pos,search.length(),replace);
211        pos = orig.find( search, pos+replace.length() );
212    }
213    return orig;
214}
215
216string cmdclean (string cmdline) {
217    string spchars = "\\`$();|{}&'\"*?<>[]!^~-#\n\r ";
218    for (uint i=0; i<spchars.length(); i++) {
219        string curchar = spchars.substr(i,1);
220        cmdline = strreplace(cmdline, curchar, "\\"+curchar);
221    }
222    return cmdline;
223}
224
225int intTransition(int from, int to, long tickStart, long duration, long tickNow) {
226    if (tickNow<0) tickNow = SDL_GetTicks();
227    return constrain(((tickNow-tickStart) * (to-from)) / duration, from, to);
228    // elapsed increments
229}
230
231void inject_user_event(enum EventCode code, void *data1, void *data2)
232{
233    SDL_UserEvent e = {
234        .type = SDL_USEREVENT,
235        .code = code,
236        .data1 = data1,
237        .data2 = data2,
238    };
239
240    /* Inject an user event, that will be handled as a "repaint"
241     * event by the InputManager */
242    SDL_PushEvent((SDL_Event *) &e);
243    DEBUG("Injecting event code %i\n", e.code);
244}
245

Archive Download this file



interactive