summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--include/sitecing/sitecing_enflesher.h13
-rw-r--r--lib/component_factory.cc19
-rw-r--r--lib/file_factory.cc1
-rw-r--r--lib/sitecing_enflesher.ll76
-rw-r--r--lib/sitecing_util.cc4
5 files changed, 93 insertions, 20 deletions
diff --git a/include/sitecing/sitecing_enflesher.h b/include/sitecing/sitecing_enflesher.h
index 512a358..8bc43a0 100644
--- a/include/sitecing/sitecing_enflesher.h
+++ b/include/sitecing/sitecing_enflesher.h
@@ -1,66 +1,79 @@
#ifndef __SITECING_SITECING_ENFLESHER_H
#define __SITECING_SITECING_ENFLESHER_H
#include <fstream>
#include <string>
using namespace std;
/**
* @file
* @brief The preprocessed source builder.
*/
#ifndef sitecing_enflesher_flexlexer_once
#define sitecing_enflesher_flexlexer_once
#undef yyFlexLexer
#define yyFlexLexer sitecing_enflesherFlexLexer
#include <FlexLexer.h>
#undef yyFlexLexerOnce
#endif
class sitecing_parser;
/**
* The enfleshing of the skeleton file according to the in-memory parsed
* component source.
*/
class sitecing_enflesher : public sitecing_enflesherFlexLexer {
public:
/**
* It is time to anchor output with the #line directive.
*/
bool anchor_time;
/**
* The file currently being written is supposed to have #line
* directives all around the place.
*/
bool anchoraged;
/**
* The reference to the parser object containg the parsed source.
*/
sitecing_parser& parser;
/**
* The output stream.
*/
ofstream outs;
+ /**
+ * the outs stream destination file.
+ * @see outs
+ */
+ string outs_filename;
/**
* @param p The parser object containing preparsed data.
*/
sitecing_enflesher(sitecing_parser& p)
: parser(p), anchor_time(true) { }
/**
* Do the job.
*/
void enflesh();
virtual void LexerOutput(const char *buf,int size);
virtual int yylex();
/**
* Put a #line anchor into output.
*/
void anchor();
+
+ /**
+ * Close previously opened output stream, rename to the 'correct'
+ * destination filename, if needed, and open new file.
+ * @see outs
+ * @see outs_filename
+ */
+ void outs_open(const string& nfile);
};
#endif /* __SITECING_SITECING_ENFLESHER_H */
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
index f8666dc..b8f5a16 100644
--- a/lib/component_factory.cc
+++ b/lib/component_factory.cc
@@ -1,175 +1,180 @@
#ifdef USE_PCH
#include "pch.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
using namespace std;
#include "sitecing/component_factory.h"
#include "sitecing/sitecing_util.h"
#include "sitecing/sitecing_parser.h"
#include "sitecing/sitecing_exception.h"
#endif
namespace sitecing {
- static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors" };
+ static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" };
static const char *cc_targets[] = { ".o", ".d" };
component_factory::component_factory(configuration& c)
: config(c),
root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'),
root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'),
root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') {
}
void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
deps.clear();
string dp = normalize_path(dst,strip_trailing_slash);
// source documents
try { // XXX: or just compare it off?
string noro = strip_prefix(dp,root_source);
return;
}catch(utility_no_affix& una) {
}
// .so binaries
try {
string noso = strip_suffix(dp,".so");
string noro = strip_prefix(noso,root_so);
deps.push_back(root_intermediate+noro+".o");
config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps);
if(co_so_deps) {
for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i)
deps.push_back(*i);
}
return;
}catch(utility_no_prefix& unp) {
throw konforka::exception(CODEPOINT,"component is outside of component root");
}catch(utility_no_suffix& uns) {
}
// preprocessor targets
for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
try {
string nos = strip_suffix(dp,pp_targets[ppt]);
string noro = strip_prefix(nos,root_intermediate);
deps.push_back(root_source+noro);
ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in);
if(imports.good()) {
string str;
while(!imports.eof()) {
imports >> str;
if(!str.empty())
deps.push_back(root_intermediate+str+".classname");
}
}
ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in);
if(ancestors.good()) {
string str;
while(!ancestors.eof()) {
ancestors >> str;
if(!str.empty())
deps.push_back(root_intermediate+str+".classname");
}
}
config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps);
if(co_intermediate_deps) {
for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i)
deps.push_back(*i);
}
return;
}catch(utility_no_affix& una) {
// do nothing. must be a cpp dependency.
}
}
// compiler targets
for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
try {
string nos = strip_suffix(dp,cc_targets[cct]);
string noro = strip_prefix(nos,root_intermediate);
deps.push_back(root_intermediate+noro+".cc");
config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps);
if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) {
ifstream df((root_intermediate+noro+".d").c_str(),ios::in);
if(df.good()) {
string str;
while(!df.eof()) {
df >> str;
if(str.find_first_of("\\:")==string::npos)
deps.push_back(combine_path(config.root_source+noro,str));
}
}
}
// XXX: extra deps like IntermediateDeps?
}catch(utility_no_affix& una) {
// do nothing.
}
}
}
bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
string dp = normalize_path(dst,strip_trailing_slash);
// XXX: or just compare it off, instead of throwing things around.
try {
- strip_prefix(dp,root_intermediate);
- return file_factory::is_uptodate(dst,deps);
- }catch(utility_no_prefix& unp) {
+ string noro = strip_prefix(dp,root_intermediate);
+ for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
+ try {
+ string nos = strip_suffix(noro,pp_targets[ppt]);
+ return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps);
+ }catch(utility_no_suffix& uns) { }
}
+ bool rv = file_factory::is_uptodate(dst,deps);
+ return rv;
+ }catch(utility_no_prefix& unp) { }
try {
strip_prefix(dp,root_so);
return file_factory::is_uptodate(dst,deps);
- }catch(utility_no_prefix& unp) {
- }
+ }catch(utility_no_prefix& unp) { }
return true;
}
void component_factory::build(const string& dst) {
string dp = normalize_path(dst,strip_trailing_slash);
// sources
try {
string noro = strip_prefix(dp,root_source);
// building the sources is left up to developer
return;
}catch(utility_no_prefix& unp) {
}
// .so files
try {
string noso = strip_suffix(dp,".so");
string noro = strip_prefix(noso,root_so);
string o = root_intermediate+noro+".o";
if(access(o.c_str(),R_OK))
throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")");
make_path(dir_name(root_so+noro),0755);
file_lock lock_cc(root_intermediate+noro+".o.lock");
file_lock lock_so(root_so+noro+".so.lock");
int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdO<0)
throw konforka::exception(CODEPOINT,"failed to open/create linker stdout");
int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdE<0) {
close(stdO);
throw konforka::exception(CODEPOINT,"failed to open/create linker stderr");
}
list<string> args;
config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags);
if(co_ld_flags) {
args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end());
}
args.push_back("-shared");
args.push_back(o);
file_list_t ancestors;
get_ancestors(noro,ancestors);
for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) {
string aso=root_so+*i+".so";
make(aso);
args.push_back(aso);
}
args.push_back("-o"); args.push_back(dp);
// TODO: "g++" configurable
int rv = execute("g++",args,stdO,stdE);
if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
@@ -204,96 +209,98 @@ namespace sitecing {
}
list<string> args;
config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags);
if(co_cpp_flags) {
args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end());
}
// TODO: maybe move it to separare config option like CoreCPPFLags?
args.push_back("-I"+root_intermediate);
args.push_back("-I"+root_source);
args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d");
args.push_back("-c");
args.push_back(cc);
args.push_back("-o"); args.push_back(o);
// TODO: "g++" configurable
int rv = execute("g++",args,stdO,stdE);
if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
throw compile_error(CODEPOINT,"failed to compile component",noro);
return;
}catch(utility_no_affix& una) {
// do nothing, not a compiler target
}
}
// preprocessor targets
for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
try {
string nos = strip_suffix(dp,pp_targets[ppt]);
string noro = strip_prefix(nos,root_intermediate);
string src = root_source+noro;
if(access(src.c_str(),R_OK))
throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
make_path(dir_name(root_intermediate+noro),0755);
file_lock lock(root_intermediate+noro+".lock");
sitecing_parser parser(*this);
config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton);
if(co_skeleton)
parser.skeleton = co_skeleton->skeleton;
static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash);
for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) {
string::size_type lc = parser.class_name.find_first_of(id_chars,illc);
int n = ((lc==string::npos)?parser.class_name.length():lc)-illc;
parser.class_name.replace(illc,n,n,'_');
}
parser.class_name = "_SCC_"+parser.class_name;
parser.output_basename = nos;
parser.component_basename = noro;
try {
parser.preprocess(src);
+ string sf = root_intermediate+noro+".pp_stamp";
+ ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp
}catch(preprocessor_error& pe) {
pe.component_name = noro;
pe.see(CODEPOINT);
throw;
}
return;
}catch(utility_no_affix& una) {
// must be a crap from .d file
}
}
cerr << "ignoring build request for " << dp << endl;
}
int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) {
// XXX: is it right that we do stdio/stderr tricks outside of the function?
cerr << "executing: " << cmd;
vector<const char*> argv(args.size()+2);
argv[0]=cmd.c_str();
int an = 1;
for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
cerr << " " << *i ;
argv[an++] = i->c_str();
}
cerr << endl;
argv[an++]=NULL;
pid_t pid = vfork();
if(pid==-1) {
close(stdo); close(stde);
throw konforka::exception(CODEPOINT,"failed to vfork()");
}
if(!pid) {
// child
if(dup2(stdo,1)!=1)
_exit(-1);
if(dup2(stde,2)!=2)
_exit(-1);
close(0);
execvp(cmd.c_str(),(char**)&argv.front());
_exit(-1);
}
// parent
close(stdo); close(stde);
int rv;
if(waitpid(pid,&rv,0)<0)
throw konforka::exception(CODEPOINT,"failed to waitpid()");
return rv;
}
diff --git a/lib/file_factory.cc b/lib/file_factory.cc
index c6b5748..7ca7b86 100644
--- a/lib/file_factory.cc
+++ b/lib/file_factory.cc
@@ -1,55 +1,56 @@
#ifdef USE_PCH
#include "pch.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <konforka/exception.h>
using namespace std;
#include "sitecing/file_factory.h"
#endif
namespace sitecing {
bool file_factory::is_uptodate(const string& dst,file_list_t* deps) {
file_list_t deplist;
file_list_t *fl = deps?deps:&deplist;
get_dependencies(dst,*fl);
struct stat stdst;
if(stat(dst.c_str(),&stdst))
return false;
for(file_list_t::const_iterator i=fl->begin();i!=fl->end();i++) {
struct stat stdep;
if(stat(i->c_str(),&stdep))
return false;
if(stdst.st_mtime<stdep.st_mtime)
return false;
if(!is_uptodate(*i))
return false;
}
return true;
}
void file_factory::make(const string& dst) {
try {
depth++;
if(depth>25)
throw konforka::exception(CODEPOINT,"recursed too deeply.");
file_list_t deps;
if(!is_uptodate(dst,&deps)) {
for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++)
make(*i);
+ if(!is_uptodate(dst,&deps))
build(dst);
}
depth--;
}catch(konforka::exception& ke) {
depth--;
ke.see(CODEPOINT);
throw;
}catch(...) {
depth--;
throw;
}
}
}
diff --git a/lib/sitecing_enflesher.ll b/lib/sitecing_enflesher.ll
index 5f631d7..46489c7 100644
--- a/lib/sitecing_enflesher.ll
+++ b/lib/sitecing_enflesher.ll
@@ -1,91 +1,81 @@
%{
#include <iostream>
#include <fstream>
#include <cassert>
#include <stdexcept>
using namespace std;
#include "sitecing/sitecing_exception.h"
using namespace sitecing;
#define sitecing_enflesher_flexlexer_once
#include "sitecing/sitecing_enflesher.h"
#include "sitecing/sitecing_parser.h"
#undef yyFlexLexer
#define yyFlexLexer sitecing_enflesherFlexLexer
%}
%option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug
ID [A-Za-z_][A-Za-z0-9_]*
%%
^\%\%\#[^\n]+\n {
string line = yytext;
line.erase(0,3);
line.erase(line.length()-1);
- outs.flush();
- outs.close();
- outs.clear();
- outs.open((parser.output_basename+line).c_str(),ios::trunc);
- if(!outs.good())
- throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ outs_open(parser.output_basename+line);
anchor();
anchoraged = true;
}
^\%\%[^\n]+\n {
string line = yytext;
line.erase(0,2);
line.erase(line.length()-1);
- outs.flush();
- outs.close();
- outs.clear();
- outs.open((parser.output_basename+line).c_str(),ios::trunc);
- if(!outs.good())
- throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ outs_open(parser.output_basename+line);
anchoraged = false;
}
\<\%component_basename\%\> outs << parser.component_basename; anchor_time = true;
\<\%impl\%\> outs << parser.impl; anchor_time = true;
\<\%member_functions:impl\%\> {
for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
outs << i->type << " " << parser.class_name << "::";
if(i->name.empty()) {
outs << parser.class_name << "()";
bool first = true;
for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
if(i->initializer.empty())
continue;
if(first) {
outs << ":";
first=false;
}else{
outs << ",";
}
if(i->bComponent) {
outs << i->name << "(NULL)";
}else {
outs << i->name << "(" << i->initializer << ")";
}
}
}else if(i->name == "~")
outs << "~" << parser.class_name << "()";
else
outs << i->name << i->args;
outs << "{\n" << i->body << "\n}\n";
}
anchor_time = true;
}
\<\%class_name\%\> outs << parser.class_name; anchor_time = true;
\<\%baseclass_header\%\> outs << parser.base_header; anchor_time = true;
\<\%decl\%\> outs << parser.decl; anchor_time = true;
\<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true;
\<\%member_variables:decl\%\> {
for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
if(i->bComponent) {
if(i->type.empty()) {
i->type = parser.factory.get_classname(i->initializer);
}
if(i->bTypeOnly) {
outs << "typedef " << i->type << " " << i->name << ";\n";
}else{
outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n";
@@ -152,51 +142,113 @@ ID [A-Za-z_][A-Za-z0-9_]*
}
anchor_time = true;
}
\<\%ancestors:base_clause_part\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << ", virtual public " << parser.factory.get_classname(i->path);
}
}
\<\%ancestors:typedefs\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n";
}
anchor_time = true;
}
\<\%ancestors:import\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << i->name << "::__do_imports();\n";
}
anchor_time = true;
}
\n {
if(anchor_time)
anchor();
ECHO;
}
. ECHO;
%%
void sitecing_enflesher::LexerOutput(const char *buf,int size) {
outs.write(buf,size);
}
void sitecing_enflesher::enflesh() {
ifstream ifs(parser.skeleton.c_str());
if(!ifs.good())
throw preprocessor_error(CODEPOINT,"failed to open skeleton file");
switch_streams(&ifs,NULL);
yylex();
}
void sitecing_enflesher::anchor() {
if(!anchoraged)
return;
outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
anchor_time = false;
}
+
+void sitecing_enflesher::outs_open(const string& nfile) {
+ if(!outs_filename.empty()) {
+ outs.flush();
+ outs.close();
+ outs.clear();
+ /*
+ * compare source and destination files.
+ *
+ * one can also keep a hash for the old one and compute one for the
+ * output while writing, but I'm not sure if it's any better. Surely a
+ * bit less accurate, unless we're going to compare it in case of
+ * difference, anyway.
+ */
+ bool overwrite = false;
+ struct stat st_s, st_d;
+ string fn_s = outs_filename+".new";
+ string fn_d = outs_filename;
+ if(stat(fn_d.c_str(),&st_d)) {
+ overwrite = true;
+ }else{
+ if(stat(fn_s.c_str(),&st_s))
+ throw preprocessor_error(CODEPOINT,"failed to stat() supposedly created file");
+ if(st_s.st_size!=st_d.st_size) {
+ overwrite = true;
+ }else{
+ ifstream i_s(fn_s.c_str(),ios::in);
+ if(!i_s)
+ throw preprocessor_error(CODEPOINT,"failed to open supposedly created file");
+ ifstream i_d(fn_d.c_str(),ios::in);
+ if(!i_d)
+ throw preprocessor_error(CODEPOINT,"failed to open the old preprocessed source");
+ off_t remaining = st_s.st_size;
+ char t1[2048];
+ char t2[sizeof(t1)];
+ while(remaining) {
+ int rb = remaining;
+ if(rb>sizeof(t1))
+ rb = sizeof(t1);
+ if(i_s.read(t1,rb).gcount()!=rb)
+ throw preprocessor_error(CODEPOINT,"error reading just created file");
+ if(i_d.read(t2,rb).gcount()!=rb)
+ throw preprocessor_error(CODEPOINT,"error reading the old preprocessed source");
+ if(memcmp(t1,t2,rb)) {
+ overwrite = true;
+ break;
+ }
+ remaining -= rb;
+ }
+ }
+ }
+ if(overwrite) {
+ cerr << "renaming '" << fn_s << "'" << endl;
+ if(rename(fn_s.c_str(),fn_d.c_str()))
+ throw preprocessor_error(CODEPOINT,"failed to rename() generated output");
+ }
+ }
+ outs_filename = nfile;
+ outs.open((nfile+".new").c_str(),ios::trunc);
+ if(!outs.good())
+ throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+}
/*
* vim:set ft=lex:
*/
diff --git a/lib/sitecing_util.cc b/lib/sitecing_util.cc
index 5466b28..f892a60 100644
--- a/lib/sitecing_util.cc
+++ b/lib/sitecing_util.cc
@@ -11,103 +11,103 @@
#include <iostream>
#include <fstream>
#include <cassert>
#include "sitecing/sitecing_util.h"
#endif
namespace sitecing {
/*
* XXX: all of these utilities could be sheerly optimized.
*/
string normalize_path(const string& path,int opts) {
const char *s = path.c_str();
string rv;
string::size_type notslash = 0;
if( (*s)=='.' && s[1]=='/' )
s+=2;
if(opts&strip_leading_slash)
for(;(*s) && (*s)=='/';s++);
for(;*s;s++) {
if( (*s)=='/' ) {
if(s[1]=='/')
continue;
if(s[1]=='.' && s[2]=='/') {
s+=2;
continue;
}
}
if(opts&restrict_dotdot) {
if(
( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' ) // "^../"
|| ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)"
)
throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered");
}
rv += *s;
if( (*s) != '/' )
notslash=rv.length();
}
if(!(opts&strip_trailing_slash))
notslash++;
if(notslash<rv.length())
rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash
return rv;
}
string strip_prefix(const string& str,const string& prefix) {
- if(str.compare(0,prefix.length(),prefix))
+ if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix))
throw utility_no_prefix(CODEPOINT,"no such prefix");
return str.substr(prefix.length());
}
string strip_suffix(const string& str,const string& suffix) {
- if(str.compare(str.length()-suffix.length(),suffix.length(),suffix))
+ if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix))
throw utility_no_suffix(CODEPOINT,"no such suffix");
return str.substr(0,str.length()-suffix.length());
}
string dir_name(const string& filename) {
string::size_type sl = filename.find_last_of('/');
if(sl==string::npos)
return ""; // no slashes -- no dir.
string::size_type nosl = filename.find_last_not_of('/',sl);
if(nosl==string::npos)
return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir?
return filename.substr(0,nosl+1);
}
void make_path(const string& path,mode_t mode) {
struct stat st;
for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) {
if(!sl)
continue;
string p = path.substr(0,sl);
if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) {
if(mkdir(p.c_str(),mode))
throw konforka::exception(CODEPOINT,"failed to mkdir()");
}
}
if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) {
if(mkdir(path.c_str(),mode))
throw konforka::exception(CODEPOINT,"failed to mkdir()");
}
}
void file_lock::lock(const string& f) {
unlock();
fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
if(fd<0)
throw konforka::exception(CODEPOINT,"failed to open/create lockfile");
try {
lock();
}catch(konforka::exception& ke) {
ke.see(CODEPOINT);
close(fd); fd=-1;
throw;
}catch(...) {
close(fd); fd=-1;
throw;
}
}
void file_lock::lock() {