12#include "wvstringmask.h"
15#include "wvlinkerhack.h"
31 : filename(_filename), create_mode(_create_mode), log(_filename), save_cb(_save_cb)
35 memset(&old_st, 0,
sizeof(old_st));
50UniIniGen::~UniIniGen()
57 WvFile file(filename, O_RDONLY);
61 if (file.
isok() && fstat(file.
getrfd(), &statbuf) == -1)
63 log(WvLog::Warning,
"Can't stat '%s': %s\n",
64 filename, strerror(errno));
68 if (file.
isok() && (statbuf.st_mode & S_ISVTX))
75 && statbuf.st_ctime == old_st.st_ctime
76 && statbuf.st_dev == old_st.st_dev
77 && statbuf.st_ino == old_st.st_ino
78 && statbuf.st_blocks == old_st.st_blocks
79 && statbuf.st_size == old_st.st_size)
81 log(WvLog::Debug3,
"refresh: file hasn't changed; do nothing.\n");
84 memcpy(&old_st, &statbuf,
sizeof(statbuf));
90 "Can't open '%s' for reading: %s\n"
91 "...starting with blank configuration.\n",
92 filename, file.errstr());
116 WVTCL_NASTY_NEWLINES,
122 int len = strlen(str);
123 if (len == 0)
continue;
132 if (str[0] ==
'[' && str[len - 1] ==
']')
156 assert(*value ==
'=');
168 "Ignoring malformed input line: \"%s\"\n", word);
175 size_t offset = buf.
strchr(
'\n');
180 "XXX Ignoring malformed input line: \"%s\"\n", line1);
187 "Error reading from config file: %s\n", file.errstr());
199 oldtree->
compare(newtree, wv::bind(&UniIniGen::refreshcomparator,
this,
232 a->
visit(wv::bind(&UniIniGen::notify_deleted,
this, _1, _2),
248bool UniIniGen::commit_atomic(
WvStringParm real_filename)
252 if (lstat(real_filename, &statbuf) == -1)
258 if (!S_ISREG(statbuf.st_mode))
261 WvString tmp_filename(
"%s.tmp%s", real_filename, getpid());
262 WvFile file(tmp_filename, O_WRONLY|O_TRUNC|O_CREAT, 0000);
266 log(WvLog::Warning,
"Can't write '%s': %s\n",
267 tmp_filename, strerror(errno));
268 unlink(tmp_filename);
275 mode_t theumask = umask(0);
277 fchmod(file.getwfd(), create_mode & ~theumask);
281 if (file.geterr() || rename(tmp_filename, real_filename) == -1)
283 log(WvLog::Warning,
"Can't write '%s': %s\n",
284 filename, strerror(errno));
285 unlink(tmp_filename);
304 WvFile file(filename, O_WRONLY|O_TRUNC|O_CREAT, create_mode);
309 log(WvLog::Warning,
"Can't write '%s': %s\n",
310 filename, file.errstr());
315 char resolved_path[PATH_MAX];
317 if (realpath(filename, resolved_path) != NULL)
318 real_filename = resolved_path;
320 if (!commit_atomic(real_filename))
322 WvFile file(real_filename, O_WRONLY|O_TRUNC|O_CREAT, create_mode);
325 if (fstat(file.
getwfd(), &statbuf) == -1)
327 log(WvLog::Warning,
"Can't write '%s' ('%s'): %s\n",
328 filename, real_filename, strerror(errno));
332 fchmod(file.
getwfd(), (statbuf.st_mode & 07777) | S_ISVTX);
340 statbuf.st_mode = statbuf.st_mode & ~S_ISVTX;
341 fchmod(file.
getwfd(), statbuf.st_mode & 07777);
344 log(WvLog::Warning,
"Error writing '%s' ('%s'): %s\n",
345 filename, real_filename, file.errstr());
357static bool absolutely_needs_escape(
WvStringParm s,
const char *sepchars)
361 bool inescape =
false, inspace =
false;
363 if (isspace((
unsigned char)*s))
366 for (cptr = s; *cptr; cptr++)
370 else if (!numbraces && strchr(sepchars, *cptr))
372 else if (*cptr ==
'\\')
374 else if (*cptr ==
'{')
376 else if (*cptr ==
'}')
379 inspace = isspace((
unsigned char)*cptr);
385 if (inescape || inspace)
396static void printsection(
WvStream &file,
const UniConfKey &key, UniIniGen::SaveCallback save_cb)
401 if (absolutely_needs_escape(key,
"\r\n[]"))
422 if (absolutely_needs_escape(_key,
"\r\n[]=#\""))
431 if (absolutely_needs_escape(_value,
"\r\n"))
452 bool recursive, UniIniGen::SaveCallback save_cb)
455 for (it.rewind(); it.next(); )
472 printsection(file, toplevel.
fullkey(), save_cb);
473 printedsection =
true;
475 printkey(file, node.
fullkey(&toplevel), node.
value(), save_cb);
480 save_sect(file, toplevel, node, printedsection, recursive, save_cb);
489 if (!&parent)
return;
496 if (!!parent.
value())
497 printkey(file, parent.
key(), parent.
value(), save_cb);
500 bool printedsection =
false;
502 save_sect(file, parent, parent, printedsection,
false, save_cb);
505 for (it.rewind(); it.next(); )
509 printedsection =
false;
510 save_sect(file, node, node, printedsection,
true, save_cb);
The basic interface which is included by all other XPLC interfaces and objects.
An abstract data container that backs a UniConf tree.
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
void prepend(const UniConfKey &other)
Prepends a path to this path.
bool isempty() const
Returns true if this path has zero segments (also known as root).
UniConfKey fullkey(const Sub *ancestor=NULL) const
Returns full path of this node relative to an ancestor.
void visit(const Visitor &visitor, void *userdata, bool preorder=true, bool postorder=false) const
Performs a traversal on this tree using the specified visitor function and traversal type(s).
bool compare(const Sub *other, const Comparator &comparator)
Compares this tree with another using the specified comparator function.
A plain UniConfTree that holds keys and values.
const WvString & value() const
Returns the value field.
const UniConfKey & key() const
Returns the key field.
bool haschildren() const
Returns true if the node has children.
Loads and saves ".ini"-style files similar to those used by Windows, but adapted to represent keys an...
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
UniIniGen(WvStringParm filename, int _create_mode=0666, SaveCallback _save_cb=SaveCallback())
Creates a generator which can load/modify/save a .ini file.
virtual void commit()
Commits any changes.
virtual bool refresh()
Refreshes information about a key recursively.
A UniConf generator that stores keys in memory.
virtual bool refresh()
Refreshes information about a key recursively.
virtual void commit()
Commits any changes.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
size_t used() const
Returns the number of elements in the buffer currently available for reading.
size_t strchr(int ch)
Returns the number of characters that would have to be read to find the first instance of the charact...
WvString getstr()
Returns the entire buffer as a null-terminated WvString.
void putstr(WvStringParm str)
Copies a WvString into the buffer, excluding the null-terminator.
A raw memory read-only buffer backed by a constant WvString.
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
bool isnull() const
returns true if this string is null
int getrfd() const
Returns the Unix file descriptor for reading from this stream.
virtual bool isok() const
return true if the stream is actually usable right now
int getwfd() const
Returns the Unix file descriptor for writing to this stream.
virtual void close()
Closes the file descriptors.
WvFile implements a stream connected to a file or Unix device.
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
char * blocking_getline(time_t wait_msec, int separator='\n', int readahead=1024)
This is a version of getline() that allows you to block for more data to arrive.
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
A class used to provide a masked lookup for characters in a string.
WvString is an implementation of a simple and efficient printable-string class.
WvString & unique()
make the buf and str pointers owned only by this WvString.
char * edit()
make the string editable, and return a non-const (char*)
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Functions to handle "tcl-style" strings and lists.
WvString wvtcl_unescape(WvStringParm s)
tcl-unescape a string.
WvString wvtcl_escape(WvStringParm s, const WvStringMask &nasties=WVTCL_NASTY_SPACES)
tcl-escape a string.
WvString wvtcl_getword(WvBuf &buf, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
Get a single tcl word from an input buffer, and return the rest of the buffer untouched.