1 #include <cstdio>
2 #include <cstring>
3 #include <cctype>
4 #include <ctime> // borland needs this
5 #include <sys/stat.h>
6 #if defined(_MSC_VER)
7 # include <sys/utime.h>
8 #else
9 # include <utime.h>
10 #endif
11 #if defined(_WIN32)
12 # include <io.h>
13 # define F_OK 0
14 #else
15 # include <unistd.h>
16 #endif
17 #include "sedit.h"
18 #include "setfname.h"
19
20 /*
21
22 copyright (c) 2004-2006 squell <squell@alumina.nl>
23
24 use, modification, copying and distribution of this software is permitted
25 under the conditions described in the file 'COPYING'.
26
27 */
28
29 using namespace std;
30
31 using tag::write::file;
32
33 // checks if a character is a member of the portable set
34
35 namespace {
36 const char allowed[] = " ._-()";
portable_fn(char c)37 bool portable_fn(char c)
38 {
39 return isalnum(c) || (c & 0x80) || strchr(allowed, c);
40 }
41
get_utime(const char * fname,utimbuf * buf)42 utimbuf* get_utime(const char* fname, utimbuf* buf)
43 {
44 struct stat file_info;
45 if( stat(fname, &file_info) == 0 ) {
46 buf->actime = file_info.st_atime;
47 buf->modtime = file_info.st_mtime;
48 return buf;
49 }
50 return 0;
51 }
52 }
53
vmodify(const char * fname,const function & edit) const54 bool file::vmodify(const char* fname, const function& edit) const
55 {
56 utimbuf buf, *stamp = get_utime(fname, &buf);
57
58 function::result edited = edit(m_template); // use pre-values
59
60 if(m_template.empty() || !edited.good()) {
61 bool ok = combined<interface>::vmodify(fname, edit);
62 if(m_preserve) utime(fname, stamp);
63 return ok;
64 }
65
66 string name = edited;
67 for(string::iterator p = name.begin(); p != name.end(); ++p) {
68 if(!portable_fn(*p)) *p = '_'; // replace ill. chars
69 }
70 if(const char* psep = strrchr(fname, '/')) {
71 name.insert(0, fname, psep-fname+1); // copy path prefix
72 }
73
74 const char* newfn = name.c_str();
75 if(name != fname && access(newfn, F_OK) == 0) // check if already exists
76 throw failure(newfn, ": file already exists");
77
78 bool ok = combined<interface>::vmodify(fname, edit);
79 if(m_preserve) utime(fname, stamp);
80
81 if(ok && std::rename(fname, newfn) != 0)
82 throw failure("could not rename ", fname);
83
84 return ok;
85 }
86
87