Line data Source code
1 : #define _OksBuildDll_
2 :
3 : #include "oks/file.hpp"
4 : #include "oks/kernel.hpp"
5 : #include "oks/xml.hpp"
6 : #include "oks/cstring.hpp"
7 :
8 : #include "oks_utils.hpp"
9 :
10 : #include <errno.h>
11 : #include <stdlib.h>
12 : #include <unistd.h>
13 : #include <string.h>
14 : #include <sys/stat.h>
15 :
16 : #include <fstream>
17 : #include <sstream>
18 : #include <stdexcept>
19 :
20 : #include <boost/date_time/posix_time/posix_time_types.hpp>
21 : #include <boost/date_time/posix_time/time_formatters.hpp>
22 : #include <boost/date_time/posix_time/time_parsers.hpp>
23 : #include <boost/interprocess/sync/file_lock.hpp>
24 :
25 : #include "ers/ers.hpp"
26 : #include "logging/Logging.hpp"
27 :
28 : namespace dunedaq {
29 : namespace oks {
30 : // Nasty hack to allow code generation on the fly without locking
31 : // file. Off by default
32 : bool OksFile::p_nolock_mode = false;
33 : //
34 : // Define XML formats used to store OKS schema and data files
35 : //
36 :
37 : const char OksFile::xml_info_tag[] = "info";
38 : const char OksFile::xml_include_tag[] = "include";
39 : const char OksFile::xml_file_tag[] = "file";
40 : const char OksFile::xml_comments_tag[] = "comments";
41 : const char OksFile::xml_comment_tag[] = "comment";
42 :
43 : const char OksFile::xml_file_header[] = "<?xml version=\"1.0\" encoding=\"ASCII\"?>";
44 :
45 : const char OksFile::xml_schema_file_dtd[] =
46 : "<!DOCTYPE oks-schema [\n"
47 :
48 : " <!ELEMENT oks-schema (info, (include)?, (comments)?, (class)+)>\n"
49 :
50 : " <!ELEMENT info EMPTY>\n"
51 : " <!ATTLIST info\n"
52 : " name CDATA #IMPLIED\n"
53 : " type CDATA #IMPLIED\n"
54 : " num-of-items CDATA #REQUIRED\n"
55 : " oks-format CDATA #FIXED \"schema\"\n"
56 : " oks-version CDATA #REQUIRED\n"
57 : " created-by CDATA #IMPLIED\n"
58 : " created-on CDATA #IMPLIED\n"
59 : " creation-time CDATA #IMPLIED\n"
60 : " last-modified-by CDATA #IMPLIED\n"
61 : " last-modified-on CDATA #IMPLIED\n"
62 : " last-modification-time CDATA #IMPLIED\n"
63 : " >\n"
64 :
65 : " <!ELEMENT include (file)+>\n"
66 : " <!ELEMENT file EMPTY>\n"
67 : " <!ATTLIST file\n"
68 : " path CDATA #REQUIRED\n"
69 : " >\n"
70 :
71 : " <!ELEMENT comments (comment)+>\n"
72 : " <!ELEMENT comment EMPTY>\n"
73 : " <!ATTLIST comment\n"
74 : " creation-time CDATA #REQUIRED\n"
75 : " created-by CDATA #REQUIRED\n"
76 : " created-on CDATA #REQUIRED\n"
77 : " author CDATA #REQUIRED\n"
78 : " text CDATA #REQUIRED\n"
79 : " >\n"
80 :
81 : " <!ELEMENT class (superclass | attribute | relationship | method)*>\n"
82 : " <!ATTLIST class\n"
83 : " name CDATA #REQUIRED\n"
84 : " description CDATA \"\"\n"
85 : " is-abstract (yes|no) \"no\"\n"
86 : " >\n"
87 :
88 : " <!ELEMENT superclass EMPTY>\n"
89 : " <!ATTLIST superclass name CDATA #REQUIRED>\n"
90 :
91 : " <!ELEMENT attribute EMPTY>\n"
92 : " <!ATTLIST attribute\n"
93 : " name CDATA #REQUIRED\n"
94 : " description CDATA \"\"\n"
95 : " type (bool|s8|u8|s16|u16|s32|u32|s64|u64|float|double|date|time|string|uid|enum|class) #REQUIRED\n"
96 : " range CDATA \"\"\n"
97 : " format (dec|hex|oct) \"dec\"\n"
98 : " is-multi-value (yes|no) \"no\"\n"
99 : " init-value CDATA \"\"\n"
100 : " is-not-null (yes|no) \"no\"\n"
101 : " ordered (yes|no) \"no\"\n"
102 : " >\n"
103 :
104 : " <!ELEMENT relationship EMPTY>\n"
105 : " <!ATTLIST relationship\n"
106 : " name CDATA #REQUIRED\n"
107 : " description CDATA \"\"\n"
108 : " class-type CDATA #REQUIRED\n"
109 : " low-cc (zero|one) #REQUIRED\n"
110 : " high-cc (one|many) #REQUIRED\n"
111 : " is-composite (yes|no) #REQUIRED\n"
112 : " is-exclusive (yes|no) #REQUIRED\n"
113 : " is-dependent (yes|no) #REQUIRED\n"
114 : " ordered (yes|no) \"no\"\n"
115 : " >\n"
116 :
117 : " <!ELEMENT method (method-implementation*)>\n"
118 : " <!ATTLIST method\n"
119 : " name CDATA #REQUIRED\n"
120 : " description CDATA \"\"\n"
121 : " >\n"
122 :
123 : " <!ELEMENT method-implementation EMPTY>\n"
124 : " <!ATTLIST method-implementation\n"
125 : " language CDATA #REQUIRED\n"
126 : " prototype CDATA #REQUIRED\n"
127 : " body CDATA \"\"\n"
128 : " >\n"
129 :
130 : "]>";
131 :
132 : const char OksFile::xml_data_file_dtd[] =
133 : "<!DOCTYPE oks-data [\n"
134 :
135 : " <!ELEMENT oks-data (info, (include)?, (comments)?, (obj)+)>\n"
136 :
137 : " <!ELEMENT info EMPTY>\n"
138 : " <!ATTLIST info\n"
139 : " name CDATA #IMPLIED\n"
140 : " type CDATA #IMPLIED\n"
141 : " num-of-items CDATA #REQUIRED\n"
142 : " oks-format CDATA #FIXED \"data\"\n"
143 : " oks-version CDATA #REQUIRED\n"
144 : " created-by CDATA #IMPLIED\n"
145 : " created-on CDATA #IMPLIED\n"
146 : " creation-time CDATA #IMPLIED\n"
147 : " last-modified-by CDATA #IMPLIED\n"
148 : " last-modified-on CDATA #IMPLIED\n"
149 : " last-modification-time CDATA #IMPLIED\n"
150 : " >\n"
151 :
152 : " <!ELEMENT include (file)*>\n"
153 : " <!ELEMENT file EMPTY>\n"
154 : " <!ATTLIST file\n"
155 : " path CDATA #REQUIRED\n"
156 : " >\n"
157 :
158 : " <!ELEMENT comments (comment)*>\n"
159 : " <!ELEMENT comment EMPTY>\n"
160 : " <!ATTLIST comment\n"
161 : " creation-time CDATA #REQUIRED\n"
162 : " created-by CDATA #REQUIRED\n"
163 : " created-on CDATA #REQUIRED\n"
164 : " author CDATA #REQUIRED\n"
165 : " text CDATA #REQUIRED\n"
166 : " >\n"
167 :
168 : " <!ELEMENT obj (attr | rel)*>\n"
169 : " <!ATTLIST obj\n"
170 : " class CDATA #REQUIRED\n"
171 : " id CDATA #REQUIRED\n"
172 : " >\n"
173 : " <!ELEMENT attr (data)*>\n"
174 : " <!ATTLIST attr\n"
175 : " name CDATA #REQUIRED\n"
176 : " type (bool|s8|u8|s16|u16|s32|u32|s64|u64|float|double|date|time|string|uid|enum|class|-) \"-\"\n"
177 : " val CDATA \"\"\n"
178 : " >\n"
179 : " <!ELEMENT data EMPTY>\n"
180 : " <!ATTLIST data\n"
181 : " val CDATA #REQUIRED\n"
182 : " >\n"
183 : " <!ELEMENT rel (ref)*>\n"
184 : " <!ATTLIST rel\n"
185 : " name CDATA #REQUIRED\n"
186 : " class CDATA \"\"\n"
187 : " id CDATA \"\"\n"
188 : " >\n"
189 : " <!ELEMENT ref EMPTY>\n"
190 : " <!ATTLIST ref\n"
191 : " class CDATA #REQUIRED\n"
192 : " id CDATA #REQUIRED\n"
193 : " >\n"
194 : "]>";
195 :
196 :
197 : std::string
198 0 : FailedAddInclude::fill(const OksFile& file, const std::string& include_name, const std::string& reason) noexcept
199 : {
200 0 : return ( std::string("Failed to add include \'") + include_name + "\' to file \'" + file.get_full_file_name() + "\' because:\n" + reason);
201 : }
202 :
203 : std::string
204 0 : FailedRemoveInclude::fill(const OksFile& file, const std::string& include_name, const std::string& reason) noexcept
205 : {
206 0 : return ( std::string("Failed to remove include \'") + include_name + "\' from file \'" + file.get_full_file_name() + "\' because:\n" + reason);
207 : }
208 :
209 : std::string
210 0 : FailedRenameInclude::fill(const OksFile& file, const std::string& from, const std::string& to, const std::string& reason) noexcept
211 : {
212 0 : return ( std::string("Failed to rename include of \'") + file.get_full_file_name() + "\' from \'" + from + "\' to \'" + to + "\' because:\n" + reason);
213 : }
214 :
215 : std::string
216 0 : FailedAddComment::fill(const OksFile& file, const std::string& reason) noexcept
217 : {
218 0 : return ( std::string("Failed to add new comment to file \'") + file.get_full_file_name() + "\' because:\n" + reason);
219 : }
220 :
221 : std::string
222 0 : FailedRemoveComment::fill(const OksFile& file, const std::string& creation_time, const std::string& reason) noexcept
223 : {
224 0 : return ( std::string("Failed to remove comment created at \'") + creation_time + "\' from file \'" + file.get_full_file_name() + "\' because:\n" + reason);
225 : }
226 :
227 : std::string
228 0 : FailedChangeComment::fill(const OksFile& file, const std::string& creation_time, const std::string& reason) noexcept
229 : {
230 0 : return ( std::string("Failed to change comment created at \'") + creation_time + "\' from file \'" + file.get_full_file_name() + "\' because:\n" + reason);
231 : }
232 :
233 : std::string
234 0 : FileLockError::fill(const OksFile& file, bool lock_action, const std::string& reason) noexcept
235 : {
236 0 : return ( std::string("Failed to ") + (lock_action ? "" : "un") + "lock file \'" + file.get_full_file_name() + "\' because:\n" + reason);
237 : }
238 :
239 : std::string
240 0 : FileChangeError::fill(const OksFile& file, const std::string& action, const std::string& reason) noexcept
241 : {
242 0 : return ( std::string("Failed to ") + action + " of file \'" + file.get_full_file_name() + "\' because:\n" + reason);
243 : }
244 :
245 : std::string
246 0 : FileCompareError::fill(const std::string& src, const std::string& dest, const std::string& reason) noexcept
247 : {
248 0 : return ( std::string("Failed to compare file \'") + src + "\' with \'" + dest + "\' because:\n" + reason);
249 : }
250 :
251 :
252 4 : OksFile::OksFile(const std::string& s, const std::string& ln, const std::string& ft, const std::string& ff, OksKernel * k) :
253 4 : p_short_name (s),
254 4 : p_full_name (s),
255 4 : p_logical_name (ln),
256 4 : p_type (ft),
257 4 : p_oks_format (ff),
258 4 : p_number_of_items (0),
259 4 : p_size (0),
260 4 : p_created_by (OksKernel::get_user_name()),
261 4 : p_creation_time (boost::posix_time::second_clock::universal_time()),
262 4 : p_created_on (OksKernel::get_host_name()),
263 4 : p_last_modification_time (p_creation_time),
264 4 : p_lock (),
265 4 : p_is_updated (false),
266 4 : p_is_read_only (true),
267 4 : p_last_modified (0),
268 4 : p_repository_last_modified (0),
269 4 : p_is_on_disk (false),
270 4 : p_included_by (0),
271 12 : p_kernel (k)
272 : {
273 4 : p_last_modified_on = p_created_on;
274 4 : p_last_modified_by = p_created_by;
275 4 : create_lock_name();
276 4 : check_repository();
277 4 : }
278 :
279 : void
280 260 : OksFile::clear_comments() noexcept
281 : {
282 986 : for(std::map<std::string, oks::Comment *>::iterator i = p_comments.begin(); i != p_comments.end(); ++i) {
283 726 : delete i->second;
284 : }
285 :
286 260 : p_comments.clear();
287 260 : }
288 :
289 :
290 260 : OksFile::~OksFile() noexcept
291 : {
292 260 : clear_comments();
293 260 : }
294 :
295 : OksFile&
296 0 : OksFile::operator=(const OksFile & f)
297 : {
298 0 : if (&f != this)
299 : {
300 0 : p_list_of_include_files.clear();
301 0 : clear_comments();
302 :
303 0 : p_short_name = f.p_short_name;
304 0 : p_full_name = f.p_full_name;
305 : // p_repository = f.p_repository;
306 0 : p_repository_name = f.p_repository_name;
307 0 : p_logical_name = f.p_logical_name;
308 0 : p_type = f.p_type;
309 0 : p_oks_format = f.p_oks_format;
310 0 : p_number_of_items = f.p_number_of_items;
311 0 : p_size = f.p_size;
312 0 : p_created_by = f.p_created_by;
313 0 : p_creation_time = f.p_creation_time;
314 0 : p_created_on = f.p_created_on;
315 0 : p_last_modified_by = f.p_last_modified_by;
316 0 : p_last_modification_time = f.p_last_modification_time;
317 0 : p_last_modified_on = f.p_last_modified_on;
318 0 : p_open_mode = f.p_open_mode;
319 0 : p_is_updated = f.p_is_updated;
320 0 : p_lock = f.p_lock;
321 0 : p_is_read_only = f.p_is_read_only;
322 0 : p_lock_file_name = f.p_lock_file_name;
323 0 : p_list_of_include_files = f.p_list_of_include_files;
324 0 : p_last_modified = f.p_last_modified;
325 0 : p_repository_last_modified = f.p_repository_last_modified;
326 0 : p_is_on_disk = f.p_is_on_disk;
327 0 : p_included_by = f.p_included_by;
328 0 : p_kernel = f.p_kernel;
329 :
330 0 : for (const auto& i : f.p_comments)
331 : {
332 0 : p_comments[i.first] = new oks::Comment(*i.second);
333 : }
334 : }
335 :
336 0 : return *this;
337 : }
338 :
339 :
340 : // read xml-file header from file
341 :
342 : const char _empty_str[] = "empty";
343 :
344 256 : OksFile::OksFile(std::shared_ptr<OksXmlInputStream> xmls, const std::string& sp, const std::string& fp, OksKernel * k) :
345 256 : p_short_name (sp),
346 256 : p_full_name (fp),
347 256 : p_oks_format (_empty_str, sizeof(_empty_str)-1),
348 256 : p_creation_time (boost::posix_time::not_a_date_time),
349 256 : p_last_modification_time (boost::posix_time::not_a_date_time),
350 256 : p_lock (),
351 256 : p_is_updated (false),
352 256 : p_is_read_only (true),
353 256 : p_last_modified (0),
354 256 : p_repository_last_modified (0),
355 256 : p_is_on_disk (true),
356 256 : p_included_by (0),
357 1280 : p_kernel (k)
358 : {
359 256 : const char * fname = "OksFile::OksFile()";
360 :
361 : // create_lock_name();
362 256 : check_repository();
363 :
364 :
365 : // check file header
366 :
367 256 : try {
368 :
369 : // skip an xml file header
370 :
371 256 : {
372 256 : const char * tag_start = xmls->get_tag_start();
373 :
374 256 : if(!oks::cmp_str4(tag_start, "?xml")) {
375 0 : xmls->throw_unexpected_tag(tag_start, "?xml");
376 : }
377 : }
378 :
379 : // skip possible tag attributes
380 :
381 1280 : while(true) {
382 768 : OksXmlAttribute attr(*xmls);
383 :
384 : // check for close of tag
385 :
386 768 : if(
387 1536 : oks::cmp_str1(attr.name(), ">") ||
388 768 : oks::cmp_str1(attr.name(), "/") ||
389 768 : oks::cmp_str1(attr.name(), "?")
390 : ) { break; }
391 :
392 : // check for start of info tag
393 :
394 512 : if(!oks::cmp_str7(attr.name(), "version") && !oks::cmp_str8(attr.name(), "encoding")) {
395 0 : if(!p_kernel->get_silence_mode()) {
396 0 : Oks::warning_msg(fname) << " Unexpected attribute \'" << attr.name() << "\' in the xml file header. Either \'version\' or \'encoding\' is expected.\n";
397 : }
398 : }
399 512 : }
400 :
401 : }
402 0 : catch (oks::exception & e) {
403 0 : throw oks::FailedRead("an xml file header", e);
404 0 : }
405 0 : catch (std::exception & e) {
406 0 : throw oks::FailedRead("an xml file header", e.what());
407 0 : }
408 :
409 :
410 : // skip document type declaration and comments
411 :
412 256 : {
413 256 : while(true) {
414 256 : try {
415 256 : const char * dtd = xmls->get_tag();
416 256 : const char dtd_start[] = "<!DOCTYPE ";
417 256 : if(!strncmp(dtd_start, dtd, sizeof(dtd_start) - 1)) {
418 : break;
419 : }
420 : }
421 0 : catch (oks::exception & e) {
422 0 : throw oks::FailedRead("DTD section", e);
423 0 : }
424 0 : catch (std::exception & e) {
425 0 : throw oks::FailedRead("DTD section", e.what());
426 0 : }
427 0 : }
428 : }
429 :
430 :
431 : // skip
432 :
433 256 : try {
434 256 : xmls->store_position();
435 :
436 256 : const char * a_tag = xmls->get_tag();
437 :
438 256 : const char xml_stylesheet_start[] = "<?xml-stylesheet";
439 256 : if(strncmp(xml_stylesheet_start, a_tag, sizeof(xml_stylesheet_start) - 1)) {
440 256 : xmls->restore_position();
441 : }
442 : }
443 0 : catch (oks::exception & e) {
444 0 : throw oks::FailedRead("an xml-stylesheet tag or an oks tag", e);
445 0 : }
446 0 : catch (std::exception & e) {
447 0 : throw oks::FailedRead("an xml-stylesheet tag or an oks tag", e.what());
448 0 : }
449 :
450 : // read start-of-tag
451 :
452 256 : try {
453 256 : xmls->get_tag_start();
454 : }
455 0 : catch (oks::exception & e) {
456 0 : throw oks::FailedRead("tag", e);
457 0 : }
458 0 : catch (std::exception & e) {
459 0 : throw oks::FailedRead("tag", e.what());
460 0 : }
461 :
462 :
463 : // read info tag
464 :
465 256 : try {
466 256 : const char * tag_start = xmls->get_tag_start();
467 :
468 256 : if(!oks::cmp_str4(tag_start, xml_info_tag)) {
469 0 : xmls->throw_unexpected_tag(tag_start, xml_info_tag);
470 : }
471 : }
472 0 : catch (oks::exception & e) {
473 0 : throw oks::FailedRead("<info> tag", e);
474 0 : }
475 0 : catch (std::exception & e) {
476 0 : throw oks::FailedRead("<info> tag", e.what());
477 0 : }
478 :
479 :
480 256 : std::string oks_version;
481 :
482 :
483 : // read class attributes
484 :
485 3072 : try {
486 3072 : while(true) {
487 3072 : OksXmlAttribute attr(*xmls);
488 :
489 : // check for close of tag
490 :
491 3072 : if(oks::cmp_str1(attr.name(), ">") || oks::cmp_str1(attr.name(), "/")) { break; }
492 :
493 : // check for known info' attributes
494 :
495 2816 : else if(oks::cmp_str4 (attr.name(), "name")) p_logical_name.assign(attr.value(), attr.value_len());
496 2560 : else if(oks::cmp_str4 (attr.name(), "type")) p_type.assign(attr.value(), attr.value_len());
497 2304 : else if(oks::cmp_str10(attr.name(), "oks-format")) p_oks_format.assign(attr.value(), attr.value_len());
498 2048 : else if(oks::cmp_str10(attr.name(), "created-by")) p_created_by.assign(attr.value(), attr.value_len());
499 1792 : else if(oks::cmp_str10(attr.name(), "created-on")) p_created_on.assign(attr.value(), attr.value_len());
500 1536 : else if(oks::cmp_str11(attr.name(), "oks-version")) oks_version.assign(attr.value(), attr.value_len());
501 1280 : else if(oks::cmp_str12(attr.name(), "num-of-items")) p_number_of_items = atol(attr.value());
502 1024 : else if(oks::cmp_str13(attr.name(), "creation-time")) p_creation_time = oks::str2time(attr.value(), attr.value_len(), p_full_name.c_str());
503 768 : else if(oks::cmp_str15(attr.name(), "num-of-includes")) continue; // ignore this value
504 768 : else if(oks::cmp_str16(attr.name(), "last-modified-by")) p_last_modified_by.assign(attr.value(), attr.value_len());
505 512 : else if(oks::cmp_str16(attr.name(), "last-modified-on")) p_last_modified_on.assign(attr.value(), attr.value_len());
506 256 : else if(!strcmp(attr.name(), "last-modification-time")) p_last_modification_time = oks::str2time(attr.value(), attr.value_len(), p_full_name.c_str());
507 : else {
508 0 : p_oks_format.clear();
509 0 : xmls->throw_unexpected_tag(attr.name(), "info\'s tags");
510 : }
511 : }
512 : }
513 0 : catch(oks::exception & e) {
514 0 : throw oks::FailedRead("<info> tag attribute", e);
515 0 : }
516 0 : catch (std::exception & e) {
517 0 : throw oks::FailedRead("<info> tag attribute", e.what());
518 0 : }
519 :
520 : // read include and comments sections
521 432 : while(true) {
522 432 : xmls->store_position();
523 :
524 432 : bool read_include = false;
525 :
526 432 : try {
527 432 : const char * tag_start = xmls->get_tag_start();
528 432 : if(oks::cmp_str7(tag_start, xml_include_tag)) { read_include = true; }
529 256 : else if(oks::cmp_str8(tag_start, xml_comments_tag)) { read_include = false; }
530 149 : else { xmls->restore_position(); return; }
531 : }
532 0 : catch (oks::exception & e) {
533 0 : throw oks::FailedRead("a tag", e);
534 0 : }
535 0 : catch (std::exception & e) {
536 0 : throw oks::FailedRead("a tag", e.what());
537 0 : }
538 :
539 283 : if(read_include) {
540 728 : while(true) {
541 452 : try {
542 :
543 452 : {
544 452 : const char * tag_start = xmls->get_tag_start();
545 452 : if(!oks::cmp_str4(tag_start, xml_file_tag)) {
546 176 : if(!oks::cmp_str8(tag_start, "/include")) { xmls->throw_unexpected_tag(tag_start + 1, xml_file_tag); }
547 : break;
548 : }
549 : }
550 :
551 828 : while(true) {
552 552 : OksXmlAttribute attr(*xmls);
553 :
554 : // check for close of tag
555 552 : if(oks::cmp_str1(attr.name(), ">") || oks::cmp_str1(attr.name(), "/")) { break; }
556 :
557 : // check for known info' attributes
558 276 : else if(oks::cmp_str4(attr.name(), "path")) p_list_of_include_files.push_back(std::string(attr.value(),attr.value_len()));
559 : else {
560 0 : p_oks_format.clear();
561 0 : xmls->throw_unexpected_tag(attr.name(), "path");
562 : }
563 276 : }
564 :
565 : }
566 0 : catch (oks::exception & e) {
567 0 : throw oks::FailedRead("<file> tag", e);
568 0 : }
569 0 : catch (std::exception & e) {
570 0 : throw oks::FailedRead("<file> tag", e.what());
571 0 : }
572 276 : }
573 : }
574 : else {
575 1559 : while(true) {
576 833 : try {
577 :
578 833 : {
579 833 : const char * tag_start = xmls->get_tag_start();
580 833 : if(!oks::cmp_str7(tag_start, xml_comment_tag)) {
581 107 : if(!oks::cmp_str9(tag_start, "/comments")) { xmls->throw_unexpected_tag(tag_start, xml_comment_tag); }
582 107 : return;
583 : }
584 : }
585 :
586 726 : std::unique_ptr<oks::Comment> comment( new oks::Comment() );
587 726 : std::string creation_time;
588 :
589 7986 : while(true) {
590 4356 : OksXmlAttribute attr(*xmls);
591 :
592 : // check for close of tag
593 4356 : if(oks::cmp_str1(attr.name(), ">") || oks::cmp_str1(attr.name(), "/")) { break; }
594 :
595 : // check for known info' attributes
596 3630 : else if(oks::cmp_str4 (attr.name(), "text")) comment->p_text.assign(attr.value(), attr.value_len());
597 2904 : else if(oks::cmp_str6 (attr.name(), "author")) comment->p_author.assign(attr.value(), attr.value_len());
598 2178 : else if(oks::cmp_str10(attr.name(), "created-by")) comment->p_created_by.assign(attr.value(), attr.value_len());
599 1452 : else if(oks::cmp_str10(attr.name(), "created-on")) comment->p_created_on.assign(attr.value(), attr.value_len());
600 726 : else if(oks::cmp_str13(attr.name(), "creation-time")) creation_time.assign(attr.value(), attr.value_len());
601 : else {
602 0 : p_oks_format.clear();
603 0 : xmls->throw_unexpected_tag(attr.name(), "comment\'s tags");
604 : }
605 3630 : }
606 :
607 726 : comment->validate(creation_time);
608 :
609 726 : if(p_comments.find(creation_time) != p_comments.end()) {
610 0 : std::ostringstream text;
611 0 : text << "The comment created at \'" << creation_time << "\' was already defined in this file";
612 0 : throw std::runtime_error(text.str().c_str());
613 0 : }
614 :
615 726 : p_comments[creation_time] = comment.release();
616 :
617 726 : }
618 0 : catch (oks::exception & e) {
619 0 : throw oks::FailedRead("<comment>", e);
620 0 : }
621 0 : catch (std::exception & e) {
622 0 : throw oks::FailedRead("<comment>", e.what());
623 0 : }
624 726 : }
625 : }
626 : }
627 256 : }
628 :
629 :
630 : void
631 726 : oks::Comment::validate(const std::string& creation_time)
632 : {
633 : // YYYYMMDDThhmmss
634 726 : if( creation_time.size() != 15 || creation_time[8] != 'T' ) {
635 0 : std::ostringstream msg;
636 0 : msg << "the creation time \'" << creation_time << "\' is not an ISO-8601 date-time";
637 0 : throw std::runtime_error(msg.str().c_str());
638 0 : }
639 :
640 726 : validate();
641 726 : }
642 :
643 : void
644 726 : oks::Comment::validate()
645 : {
646 726 : if(p_text.empty()) {
647 0 : throw std::runtime_error("text is empty");
648 : }
649 726 : }
650 :
651 0 : oks::Comment::Comment(const std::string& text, const std::string& author) :
652 0 : p_created_by (OksKernel::get_user_name()),
653 0 : p_author (author),
654 0 : p_created_on (OksKernel::get_host_name()),
655 0 : p_text (text)
656 : {
657 0 : validate();
658 0 : }
659 :
660 0 : oks::Comment::Comment(const oks::Comment& src) noexcept :
661 0 : p_created_by (src.p_created_by),
662 0 : p_author (src.p_author),
663 0 : p_created_on (src.p_created_on),
664 0 : p_text (src.p_text)
665 : {
666 0 : }
667 :
668 : void
669 0 : OksFile::add_comment(const std::string& text, const std::string& author)
670 : {
671 0 : try {
672 0 : lock();
673 : }
674 0 : catch(oks::exception& ex) {
675 0 : throw oks::FailedAddComment(*this, ex);
676 0 : }
677 :
678 0 : boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time();
679 0 : std::string creation_time = boost::posix_time::to_iso_string(now);
680 :
681 0 : try {
682 0 : std::unique_ptr<oks::Comment> comment( new oks::Comment(text, author) );
683 0 : comment->validate();
684 :
685 0 : oks::Comment *& x(p_comments[creation_time]);
686 :
687 0 : if(x == 0)
688 : {
689 0 : x = comment.release();
690 : }
691 : else
692 : {
693 0 : x->p_text += "\n-----\n";
694 0 : x->p_text.append(text);
695 : }
696 0 : }
697 0 : catch(std::exception & ex) {
698 0 : throw oks::FailedAddComment(*this, ex.what());
699 0 : }
700 :
701 0 : p_is_updated = true;
702 0 : }
703 :
704 : oks::Comment *
705 0 : OksFile::get_comment(const std::string& creation_time) noexcept
706 : {
707 0 : std::map<std::string, oks::Comment *>::const_iterator i = p_comments.find(creation_time);
708 0 : return (i == p_comments.end()) ? 0: i->second;
709 : }
710 :
711 : void
712 0 : OksFile::modify_comment(const std::string& creation_time, const std::string& text, const std::string& author)
713 : {
714 0 : if(oks::Comment * comment = get_comment(creation_time)) {
715 0 : try {
716 0 : lock();
717 : }
718 0 : catch(oks::exception& ex) {
719 0 : throw oks::FailedChangeComment(*this, creation_time, ex);
720 0 : }
721 :
722 0 : std::string saved_author(comment->p_author);
723 0 : std::string saved_text(comment->p_text);
724 :
725 0 : comment->p_author = author;
726 0 : comment->p_text = text;
727 :
728 0 : try {
729 0 : comment->validate();
730 : }
731 0 : catch(std::exception& ex) {
732 0 : comment->p_author = saved_author;
733 0 : comment->p_text = saved_text;
734 0 : throw oks::FailedChangeComment(*this, creation_time, ex.what());
735 0 : }
736 :
737 0 : p_is_updated = true;
738 0 : }
739 : else {
740 0 : throw oks::FailedChangeComment(*this, creation_time, "cannot find comment");
741 : }
742 0 : }
743 :
744 :
745 : void
746 0 : OksFile::remove_comment(const std::string& creation_time)
747 : {
748 0 : if(oks::Comment * comment = get_comment(creation_time)) {
749 0 : try {
750 0 : lock();
751 : }
752 0 : catch(oks::exception& ex) {
753 0 : throw oks::FailedRemoveComment(*this, creation_time, ex);
754 0 : }
755 :
756 0 : delete comment;
757 0 : p_comments.erase(creation_time);
758 0 : p_is_updated = true;
759 : }
760 : else {
761 0 : throw oks::FailedRemoveComment(*this, creation_time, "cannot find comment");
762 : }
763 0 : }
764 :
765 :
766 : void
767 0 : OksFile::write(OksXmlOutputStream& xmls)
768 : {
769 0 : const static std::string __data("data");
770 0 : const static std::string __schema("schema");
771 :
772 0 : try
773 : {
774 0 : const char __oks_data[] = "oks-data";
775 0 : const char __oks_schema[] = "oks-schema";
776 :
777 0 : const char * id(__oks_data);
778 0 : long id_len(sizeof(__oks_data) - 1);
779 0 : const char * dtd(xml_data_file_dtd);
780 0 : long dtd_len(sizeof(xml_data_file_dtd) - 1);
781 :
782 0 : if (p_oks_format != __data)
783 : {
784 0 : if (p_oks_format == __schema)
785 : {
786 : id = __oks_schema;
787 : id_len = sizeof(__oks_schema) - 1;
788 : dtd = xml_schema_file_dtd;
789 : dtd_len = sizeof(xml_schema_file_dtd) - 1;
790 : }
791 : else
792 : {
793 0 : throw std::runtime_error("bad oks format");
794 : }
795 : }
796 :
797 0 : {
798 0 : const char __hdr_start[] = "\n\n<!-- ";
799 0 : const char __hdr_end[] = " version 2.2 -->\n\n\n";
800 :
801 0 : std::string header(xml_file_header, sizeof(xml_file_header) - 1);
802 0 : header.append(__hdr_start, sizeof(__hdr_start) - 1);
803 0 : header.append(id, id_len);
804 0 : header.append(__hdr_end, sizeof(__hdr_end) - 1);
805 0 : header.append(dtd, dtd_len);
806 :
807 0 : xmls.put_raw(header.c_str(), header.size());
808 0 : xmls.put_raw('\n');
809 0 : xmls.put_raw('\n');
810 0 : }
811 :
812 0 : xmls.put_start_tag(id, id_len);
813 :
814 0 : xmls.put_raw('>');
815 0 : xmls.put_raw('\n');
816 0 : xmls.put_raw('\n');
817 :
818 : // "creation-time" may not be filled
819 :
820 0 : std::string created_c_str;
821 0 : if (!p_creation_time.is_not_a_date_time())
822 : {
823 0 : created_c_str = boost::posix_time::to_iso_string(p_creation_time);
824 : }
825 :
826 : // get last-modified information
827 :
828 0 : if (p_repository_name.empty())
829 : {
830 0 : p_last_modification_time = boost::posix_time::second_clock::universal_time();
831 0 : p_last_modified_by = OksKernel::get_user_name();
832 0 : p_last_modified_on = OksKernel::get_host_name();
833 : }
834 :
835 0 : std::string last_modified_c_str = boost::posix_time::to_iso_string(p_last_modification_time);
836 :
837 0 : xmls.put_start_tag(xml_info_tag, sizeof(xml_info_tag) - 1);
838 0 : xmls.put_attribute("name", sizeof("name") - 1, p_logical_name.c_str());
839 0 : xmls.put_attribute("type", sizeof("type") - 1, p_type.c_str());
840 0 : xmls.put_attribute("num-of-items", sizeof("num-of-items") - 1, p_number_of_items);
841 0 : xmls.put_attribute("oks-format", sizeof("oks-format") - 1, p_oks_format.c_str());
842 0 : xmls.put_attribute("oks-version", sizeof("oks-version") - 1, OksKernel::GetVersion());
843 0 : xmls.put_attribute("created-by", sizeof("created-by") - 1, p_created_by.c_str());
844 0 : xmls.put_attribute("created-on", sizeof("created-on") - 1, p_created_on.c_str());
845 0 : if (!created_c_str.empty())
846 0 : xmls.put_attribute("creation-time", sizeof("creation-time") - 1, created_c_str.c_str());
847 0 : if (p_repository_name.empty())
848 : {
849 0 : xmls.put_attribute("last-modified-by", sizeof("last-modified-by") - 1, p_last_modified_by.c_str());
850 0 : xmls.put_attribute("last-modified-on", sizeof("last-modified-on") - 1, p_last_modified_on.c_str());
851 0 : xmls.put_attribute("last-modification-time", sizeof("last-modification-time") - 1, last_modified_c_str.c_str());
852 : }
853 0 : xmls.put_end_tag();
854 :
855 0 : if (!p_list_of_include_files.empty())
856 : {
857 0 : xmls.put_raw('\n');
858 0 : xmls.put_start_tag(xml_include_tag, sizeof(xml_include_tag) - 1);
859 :
860 0 : xmls.put_raw('>');
861 0 : xmls.put_raw('\n');
862 :
863 0 : for (const auto& i : p_list_of_include_files)
864 : {
865 0 : xmls.put_raw(' ');
866 0 : xmls.put_start_tag(xml_file_tag, sizeof(xml_file_tag) - 1);
867 0 : xmls.put_attribute("path", sizeof("path") - 1, i.c_str());
868 0 : xmls.put_end_tag();
869 : }
870 :
871 0 : xmls.put_last_tag(xml_include_tag, sizeof(xml_include_tag) - 1);
872 0 : xmls.put_raw('\n');
873 : }
874 :
875 0 : if (!p_comments.empty())
876 : {
877 0 : xmls.put_start_tag(xml_comments_tag, sizeof(xml_comments_tag) - 1);
878 :
879 0 : xmls.put_raw('>');
880 0 : xmls.put_raw('\n');
881 :
882 0 : for (const auto& i : p_comments)
883 : {
884 0 : xmls.put_raw(' ');
885 0 : xmls.put_start_tag(xml_comment_tag, sizeof(xml_comment_tag) - 1);
886 0 : xmls.put_attribute("creation-time", sizeof("creation-time") - 1, i.first.c_str());
887 0 : xmls.put_attribute("created-by", sizeof("created-by") - 1, i.second->p_created_by.c_str());
888 0 : xmls.put_attribute("created-on", sizeof("created-on") - 1, i.second->p_created_on.c_str());
889 0 : xmls.put_attribute("author", sizeof("author") - 1, i.second->p_author.c_str());
890 0 : xmls.put_attribute("text", sizeof("text") - 1, i.second->p_text.c_str());
891 0 : xmls.put_end_tag();
892 : }
893 :
894 0 : xmls.put_last_tag(xml_comments_tag, sizeof(xml_comments_tag) - 1);
895 0 : xmls.put_raw('\n');
896 : }
897 :
898 0 : xmls.put_raw('\n');
899 0 : }
900 0 : catch (std::exception& ex)
901 : {
902 0 : throw oks::FailedSave("oks-file", p_full_name, ex.what());
903 0 : }
904 :
905 0 : p_is_on_disk = true;
906 0 : }
907 :
908 : bool
909 0 : OksFile::is_repository_file() const
910 : {
911 0 : return (!p_kernel->get_user_repository_root().empty());
912 : }
913 :
914 : void
915 260 : OksFile::check_repository()
916 : {
917 : // if(size_t len = OksKernel::get_repository_root().size()) {
918 : // if(p_full_name.size() > len && p_full_name.substr(0, len) == OksKernel::get_repository_root()) {
919 : // p_repository = GlobalRepository;
920 : // p_repository_name = p_full_name.substr(len + 1);
921 : // TLOG_DEBUG( 3 ) << "file \'" << p_full_name << "\' comes from user repository [\'" << p_repository_name << "\']";
922 : // return;
923 : // }
924 : // }
925 :
926 260 : const std::string& s(p_kernel->get_user_repository_root());
927 260 : if(size_t len = s.size()) {
928 0 : if(p_full_name.size() > len && p_full_name.substr(0, len) == s) {
929 : // p_repository = UserRepository;
930 0 : p_repository_name = p_full_name.substr(len + 1);
931 :
932 0 : TLOG_DEBUG( 3 ) << "file \'" << p_full_name << "\' comes from user repository [\'" << p_repository_name << "\']" ;
933 0 : return;
934 :
935 : // std::string repository_file = OksKernel::get_repository_root() + '/' + p_repository_name;
936 : //
937 : // struct stat buf;
938 : // if(stat(repository_file.c_str(), &buf) == 0) {
939 : // TLOG_DEBUG( 3 ) << "file \'" << p_full_name << "\' comes from user repository [\'" << p_repository_name << "\']" ;
940 : // return;
941 : // }
942 : // else {
943 : // TLOG_DEBUG( 3 ) << "file \'" << p_full_name << "\' is found in user repository [\'" << p_repository_name << "\'] but does not exist in global one [\'" << OksKernel::get_repository_root() << "\']" ;
944 : // }
945 : }
946 : }
947 :
948 260 : TLOG_DEBUG( 3 ) << "file \'" << p_full_name << "\' is not in a repository" ;
949 : // p_repository = NoneRepository;
950 260 : p_repository_name.clear();
951 : }
952 :
953 : void
954 10 : OksFile::create_lock_name()
955 : {
956 10 : p_lock_file_name = p_full_name;
957 :
958 10 : std::string::size_type idx = p_lock_file_name.find_last_of('/');
959 10 : if(idx == std::string::npos) p_lock_file_name = "./";
960 10 : else p_lock_file_name.erase(idx+1);
961 :
962 10 : const char _prefix_str[] = ".oks-lock-";
963 10 : p_lock_file_name.append(_prefix_str, sizeof(_prefix_str)-1);
964 :
965 10 : idx = p_full_name.find_last_of('/');
966 10 : std::string::size_type len(p_full_name.size());
967 10 : if(idx == std::string::npos) {
968 : idx = 0;
969 : }
970 : else {
971 10 : idx++;
972 10 : len -= idx;
973 : }
974 :
975 10 : p_lock_file_name.append(p_full_name, idx, len);
976 10 : p_lock_file_name.append(".txt");
977 10 : }
978 :
979 :
980 : // return true if lock exists and false if does not exist
981 : // the string is non-empty, if the lock file was read
982 :
983 : bool
984 10 : OksFile::get_lock_string(std::string& lock_file_contents) const
985 : {
986 10 : init_lock_name();
987 :
988 10 : lock_file_contents.clear();
989 :
990 10 : const char * lock_name = p_lock_file_name.c_str();
991 10 : struct stat buf;
992 :
993 10 : if(stat(lock_name, &buf) == 0) {
994 0 : std::ifstream f(lock_name);
995 :
996 0 : if(f.good()) {
997 0 : std::getline(f, lock_file_contents);
998 : return true;
999 : }
1000 : else {
1001 0 : lock_file_contents = "unknown [cannot read lock file \'";
1002 0 : lock_file_contents += p_lock_file_name;
1003 0 : lock_file_contents += "\']";
1004 : return true;
1005 : }
1006 0 : }
1007 :
1008 : return false;
1009 : }
1010 :
1011 : void
1012 29 : OksFile::lock()
1013 : {
1014 29 : if (p_nolock_mode) {
1015 : // Nasty hack to allow code generation on the fly without locking
1016 : // file. Just return without locking!
1017 : return;
1018 : }
1019 :
1020 29 : init_lock_name();
1021 :
1022 29 : if (p_lock != nullptr)
1023 : {
1024 : return;
1025 : }
1026 :
1027 :
1028 : // check that the file is not read-only
1029 :
1030 10 : {
1031 10 : struct stat buf;
1032 :
1033 10 : if (stat(p_full_name.c_str(), &buf) == 0)
1034 : {
1035 10 : if (OksKernel::check_read_only(this) == true)
1036 : {
1037 0 : throw oks::FileLockError(*this, true, "file is read-only");
1038 : }
1039 : }
1040 : }
1041 :
1042 :
1043 : // check lock and report problem if it exists and cannot be reset
1044 :
1045 10 : {
1046 10 : std::string lock_file_contents;
1047 :
1048 10 : if (get_lock_string(lock_file_contents))
1049 : {
1050 0 : try
1051 : {
1052 0 : boost::interprocess::file_lock lock(p_lock_file_name.c_str());
1053 :
1054 0 : if (lock.try_lock() == false)
1055 : {
1056 0 : std::ostringstream text;
1057 0 : text << "file is already locked by \"" << lock_file_contents << '\"';
1058 0 : throw oks::FileLockError(*this, true, text.str());
1059 0 : }
1060 : else
1061 : {
1062 0 : try
1063 : {
1064 0 : lock.unlock();
1065 : }
1066 0 : catch (const boost::interprocess::interprocess_exception& ex)
1067 : {
1068 0 : std::ostringstream text;
1069 0 : text << "boost::interprocess::unlock() failed: \"" << ex.what() << '\"';
1070 0 : throw oks::FileLockError(*this, false, text.str());
1071 0 : }
1072 :
1073 0 : if (!p_kernel->get_silence_mode())
1074 : {
1075 0 : Oks::warning_msg("OksFile::lock()") << "Remove obsolete lock of file \'" << p_full_name << "\' created by \n\"" << lock_file_contents << "\"\n";
1076 : }
1077 :
1078 0 : if (unlink(p_lock_file_name.c_str()) != 0)
1079 : {
1080 0 : std::ostringstream text;
1081 0 : text << "failed to remove lock file \'" << p_lock_file_name << "\':\n" << oks::strerror(errno);
1082 0 : throw oks::FileLockError(*this, false, text.str());
1083 0 : }
1084 : }
1085 0 : }
1086 0 : catch (const boost::interprocess::interprocess_exception& ex)
1087 : {
1088 0 : std::ostringstream text;
1089 0 : text << "boost::interprocess::try_lock() failed: \"" << ex.what() << '\"';
1090 0 : throw oks::FileLockError(*this, false, text.str());
1091 0 : }
1092 : }
1093 10 : }
1094 :
1095 :
1096 : // write lock file
1097 :
1098 10 : {
1099 10 : std::ofstream f(p_lock_file_name.c_str());
1100 :
1101 10 : if (!f.good())
1102 : {
1103 0 : std::ostringstream text;
1104 0 : text << "failed to create lock file \'" << p_lock_file_name << '\'';
1105 0 : throw oks::FileLockError(*this, true, text.str());
1106 0 : }
1107 :
1108 10 : try
1109 : {
1110 10 : boost::posix_time::ptime now(boost::posix_time::second_clock::universal_time());
1111 10 : f << "process " << getpid() << " on " << OksKernel::get_host_name() << " started by " << OksKernel::get_user_name() << " at " << boost::posix_time::to_simple_string(now) << " (UTC)" << std::endl;
1112 10 : f.flush();
1113 10 : f.close();
1114 : }
1115 0 : catch (std::exception& ex)
1116 : {
1117 0 : std::ostringstream text;
1118 0 : text << "failed to write lock file \'" << p_lock_file_name << "\': " << ex.what();
1119 0 : throw oks::FileLockError(*this, true, text.str());
1120 0 : }
1121 10 : }
1122 :
1123 :
1124 10 : try
1125 : {
1126 10 : p_lock.reset(new boost::interprocess::file_lock(p_lock_file_name.c_str()));
1127 :
1128 10 : if (p_lock->try_lock() == false)
1129 : {
1130 0 : throw std::runtime_error("file is locked by another process");
1131 : }
1132 : }
1133 0 : catch (const std::exception& ex)
1134 : {
1135 0 : std::ostringstream text;
1136 0 : text << "boost::interprocess::try_lock() failed: \"" << ex.what() << '\"';
1137 0 : p_lock.reset();
1138 0 : throw oks::FileLockError(*this, false, text.str());
1139 0 : }
1140 : }
1141 :
1142 : void
1143 260 : OksFile::unlock()
1144 : {
1145 260 : if (p_lock == nullptr)
1146 : return;
1147 :
1148 10 : try
1149 : {
1150 10 : p_lock->unlock();
1151 : }
1152 0 : catch (const boost::interprocess::interprocess_exception& ex)
1153 : {
1154 0 : std::ostringstream text;
1155 0 : text << "boost::interprocess::unlock() failed: \"" << ex.what() << '\"';
1156 0 : p_lock.reset();
1157 0 : throw oks::FileLockError(*this, false, text.str());
1158 0 : }
1159 :
1160 10 : p_lock.reset();
1161 :
1162 10 : if (unlink(p_lock_file_name.c_str()) != 0 && errno != ENOENT)
1163 : {
1164 0 : std::ostringstream text;
1165 0 : text << "failed to remove lock file \'" << p_lock_file_name << "\':\n" << oks::strerror(errno);
1166 0 : throw oks::FileLockError(*this, false, text.str());
1167 0 : }
1168 : }
1169 :
1170 :
1171 : std::list<std::string>::iterator
1172 8 : OksFile::find_include_file(const std::string& s)
1173 : {
1174 8 : std::list<std::string>::iterator i = p_list_of_include_files.begin();
1175 :
1176 12 : for(;i != p_list_of_include_files.end(); ++i) {if(*i == s) break;}
1177 :
1178 8 : return i;
1179 : }
1180 :
1181 :
1182 : OksFile *
1183 104 : OksFile::check_parent(const OksFile * parent_h)
1184 : {
1185 104 : if(p_included_by == 0 && parent_h != 0) {
1186 0 : p_included_by = parent_h;
1187 : }
1188 :
1189 104 : return this;
1190 : }
1191 :
1192 :
1193 : void
1194 8 : OksFile::add_include_file(const std::string& s)
1195 : {
1196 : // check if the file was already included
1197 8 : if(find_include_file(s) != p_list_of_include_files.end()) { return; }
1198 :
1199 : // lock file
1200 8 : try {
1201 8 : lock();
1202 : }
1203 0 : catch(oks::exception& ex) {
1204 0 : throw oks::FailedAddInclude(*this, s, ex);
1205 0 : }
1206 :
1207 : // try to find path to include and load it
1208 8 : try {
1209 8 : std::string path = p_kernel->get_file_path(s, this);
1210 8 : p_kernel->k_load_file(path, true, this, 0);
1211 8 : }
1212 0 : catch(std::exception& ex) {
1213 0 : throw oks::FailedAddInclude(*this, s, ex.what());
1214 0 : }
1215 :
1216 : // add include and mark file as updated
1217 8 : p_list_of_include_files.push_back(s);
1218 8 : p_is_updated = true;
1219 : }
1220 :
1221 :
1222 : void
1223 0 : OksFile::remove_include_file(const std::string& s)
1224 : {
1225 : // search included file
1226 0 : std::list<std::string>::iterator i = find_include_file(s);
1227 :
1228 : // check if the file was included
1229 0 : if(i == p_list_of_include_files.end()) {
1230 0 : throw oks::FailedRemoveInclude(*this, s, "there is no such include file");
1231 : }
1232 :
1233 : // lock file
1234 0 : try {
1235 0 : lock();
1236 : }
1237 0 : catch(oks::exception& ex) {
1238 0 : throw oks::FailedRemoveInclude(*this, s, ex);
1239 0 : }
1240 :
1241 : // remove include and mark file as updated
1242 0 : p_list_of_include_files.erase(i);
1243 0 : p_is_updated = true;
1244 :
1245 : // close file, if it is not referenced by others
1246 0 : p_kernel->k_close_dangling_includes();
1247 0 : }
1248 :
1249 :
1250 : void
1251 0 : OksFile::rename_include_file(const std::string& old_s, const std::string& new_s)
1252 : {
1253 0 : if(old_s == new_s) return;
1254 :
1255 0 : std::list<std::string>::iterator i1 = find_include_file(old_s);
1256 0 : std::list<std::string>::iterator i2 = find_include_file(new_s);
1257 :
1258 0 : if(i1 == p_list_of_include_files.end()) {
1259 0 : throw oks::FailedRenameInclude(*this, old_s, new_s, "there is no such include file");
1260 : }
1261 :
1262 0 : if(i2 != p_list_of_include_files.end()) {
1263 0 : throw oks::FailedRenameInclude(*this, old_s, new_s, "file with new name is already included");
1264 : }
1265 :
1266 0 : try {
1267 0 : lock();
1268 : }
1269 0 : catch(oks::exception& ex) {
1270 0 : throw oks::FailedRenameInclude(*this, old_s, new_s, ex);
1271 0 : }
1272 :
1273 0 : (*i1) = new_s;
1274 0 : p_is_updated = true;
1275 : }
1276 :
1277 :
1278 : void
1279 0 : OksFile::set_logical_name(const std::string& s)
1280 : {
1281 0 : if(s == p_logical_name) return;
1282 :
1283 0 : try {
1284 0 : lock();
1285 : }
1286 0 : catch(oks::exception& ex) {
1287 0 : throw oks::FileChangeError(*this, "set logical name", ex);
1288 0 : }
1289 :
1290 0 : p_logical_name = s;
1291 0 : p_is_updated = true;
1292 : }
1293 :
1294 :
1295 : void
1296 0 : OksFile::set_type(const std::string& s)
1297 : {
1298 0 : if(s == p_type) return;
1299 :
1300 0 : try {
1301 0 : lock();
1302 : }
1303 0 : catch(oks::exception& ex) {
1304 0 : throw oks::FileChangeError(*this, "set type", ex);
1305 0 : }
1306 :
1307 0 : p_type = s;
1308 0 : p_is_updated = true;
1309 : }
1310 :
1311 0 : std::ostream& operator<<(std::ostream& s, const oks::Comment& c)
1312 : {
1313 0 : s << "user \"" << c.get_created_by() << "\" (" << c.get_author() << ")"
1314 0 : << " on \"" << c.get_created_on() << "\" wrote: \"" << c.get_text() << "\"";
1315 :
1316 0 : return s;
1317 : }
1318 :
1319 :
1320 : std::ostream&
1321 0 : operator<<(std::ostream& s, const OksFile& f)
1322 : {
1323 0 : s << "OKS file\n"
1324 0 : " short file name: \'" << f.get_short_file_name() << "\'\n"
1325 0 : " full file name: \'" << f.get_full_file_name() << "\'\n"
1326 0 : " lock file name: \'" << f.get_lock_file() << "\'\n"
1327 0 : " logical name: \'" << f.get_logical_name() << "\'\n"
1328 0 : " type: \'" << f.get_type() << "\'\n"
1329 0 : " oks format: \'" << f.get_oks_format() << "\'\n"
1330 0 : " number of items: " << f.get_number_of_items() << "\n"
1331 0 : " created by: " << f.get_created_by() << "\n"
1332 0 : " creation time: " << boost::posix_time::to_simple_string(f.get_creation_time()) << "\n"
1333 0 : " created on: " << f.get_created_on() << "\n"
1334 0 : " last modified by: \'" << f.get_last_modified_by() << "\'\n"
1335 0 : " last modification time: " << boost::posix_time::to_simple_string(f.get_last_modification_time()) << "\'\n"
1336 0 : " last modified on: " << f.get_last_modified_on() << "\'\n"
1337 0 : " is " << (f.is_read_only() ? "read-only" : "read-write") << "\n"
1338 0 : " is " << (f.is_locked() ? "" : "not ") << "locked\n"
1339 0 : " is " << (f.is_updated() ? "" : "not ") << "updated\n";
1340 :
1341 0 : {
1342 0 : size_t num_of_includes = f.get_include_files().size();
1343 :
1344 0 : if (num_of_includes)
1345 : {
1346 0 : s << " contains " << num_of_includes << " include file(s)";
1347 0 : for (const auto& i : f.get_include_files())
1348 0 : s << " - \'" << i << "\'\n";
1349 : }
1350 : else
1351 : {
1352 0 : s << " contains no include files\n";
1353 : }
1354 : }
1355 :
1356 0 : {
1357 0 : size_t num_of_comments = f.get_comments().size();
1358 :
1359 0 : if (num_of_comments)
1360 : {
1361 0 : s << " contains " << num_of_comments << " comment(s)";
1362 0 : for (const auto& i : f.get_comments())
1363 0 : s << " - " << boost::posix_time::to_simple_string(boost::posix_time::from_iso_string(i.first)) << ": \'" << *i.second << "\'\n";
1364 : }
1365 : else
1366 : {
1367 0 : s << " contains no comments\n";
1368 : }
1369 : }
1370 :
1371 0 : s << "END of oks file\n";
1372 :
1373 0 : return s;
1374 : }
1375 :
1376 :
1377 : std::string
1378 256 : OksFile::make_repository_name() const
1379 : {
1380 256 : std::string name;
1381 :
1382 256 : if(!OksKernel::get_repository_root().empty()) {
1383 0 : name = OksKernel::get_repository_root() + '/' + get_repository_name();
1384 : }
1385 :
1386 256 : return name;
1387 0 : }
1388 :
1389 :
1390 : void
1391 256 : OksFile::update_status_of_file(bool update_local, bool update_repository)
1392 : {
1393 256 : struct stat buf;
1394 :
1395 256 : if(update_local == true && p_is_on_disk == true) {
1396 :
1397 256 : if(stat(p_full_name.c_str(), &buf) == 0) {
1398 256 : p_last_modified = buf.st_mtime;
1399 : }
1400 : }
1401 :
1402 256 : if(update_repository == true /*&& get_repository() == UserRepository*/) {
1403 256 : std::string full_repository_name = make_repository_name();
1404 :
1405 256 : if(!full_repository_name.empty() && stat(full_repository_name.c_str(), &buf) == 0) {
1406 0 : p_repository_last_modified = buf.st_mtime;
1407 : }
1408 256 : }
1409 256 : }
1410 :
1411 :
1412 : OksFile::FileStatus
1413 6 : OksFile::get_status_of_file() const
1414 : {
1415 6 : if(p_is_on_disk == false) {
1416 : return FileWasNotSaved;
1417 : }
1418 : else {
1419 6 : struct stat buf;
1420 :
1421 6 : if(stat(p_full_name.c_str(), &buf) != 0) {
1422 0 : return FileRemoved;
1423 : }
1424 :
1425 6 : if(buf.st_mtime != p_last_modified) {
1426 : return FileModified;
1427 : }
1428 :
1429 : // if(get_repository() == UserRepository) {
1430 : // std::string full_repository_name = make_repository_name();
1431 : //
1432 : // if(!full_repository_name.empty()) {
1433 : // if(stat(full_repository_name.c_str(), &buf) != 0) {
1434 : // return FileRepositoryRemoved;
1435 : // }
1436 : //
1437 : // if(buf.st_mtime != p_repository_last_modified) {
1438 : // return FileRepositoryModified;
1439 : // }
1440 : // }
1441 : // }
1442 : }
1443 :
1444 6 : return FileNotModified;
1445 : }
1446 :
1447 :
1448 : void
1449 0 : OksFile::rename(const std::string& short_name, const std::string& full_name)
1450 : {
1451 0 : p_short_name = short_name;
1452 0 : p_full_name = full_name;
1453 0 : create_lock_name();
1454 0 : check_repository();
1455 0 : }
1456 :
1457 : void
1458 0 : OksFile::rename(const std::string& full_name)
1459 : {
1460 0 : p_full_name = full_name;
1461 0 : create_lock_name();
1462 0 : update_status_of_file();
1463 0 : }
1464 :
1465 : void
1466 0 : OksFile::get_all_include_files(const OksKernel * kernel, std::set<OksFile *>& out)
1467 : {
1468 0 : const OksFile::Map & schema_files = kernel->schema_files();
1469 0 : const OksFile::Map & data_files = kernel->data_files();
1470 :
1471 0 : for(std::list<std::string>::iterator i = p_list_of_include_files.begin(); i != p_list_of_include_files.end(); ++i) {
1472 0 : std::string s = kernel->get_file_path(*i, this);
1473 0 : if(s.size()) {
1474 0 : OksFile::Map::const_iterator j = data_files.find(&s);
1475 0 : if(j != data_files.end()) {
1476 0 : if(out.find(j->second) != out.end()) { continue; }
1477 0 : out.insert(j->second);
1478 : }
1479 : else {
1480 0 : j = schema_files.find(&s);
1481 0 : if(j != schema_files.end()) {
1482 0 : if(out.find(j->second) != out.end()) { continue; }
1483 0 : out.insert(j->second);
1484 : }
1485 : else {
1486 0 : continue;
1487 : }
1488 : }
1489 :
1490 0 : j->second->get_all_include_files(kernel, out);
1491 : }
1492 0 : }
1493 0 : }
1494 :
1495 : // return true if the string is not info line:
1496 : // <info ... last-modification-time="nnnnnnnnTnnnnnn"/>
1497 :
1498 : static bool
1499 0 : is_not_info(const std::string& line)
1500 : {
1501 0 : static const char start_tag[] = "<info ";
1502 0 : static const char last_tag[] = "last-modification-time=\"yyyymmddThhmmss\"/>"; // 24 - is a position of first double quote
1503 :
1504 0 : const std::string::size_type len = line.length();
1505 :
1506 0 : return(
1507 0 : ( len < (sizeof(start_tag) + sizeof(last_tag)) ) ||
1508 0 : ( line.compare(0, sizeof(start_tag)-1, start_tag, sizeof(start_tag)-1) != 0 ) ||
1509 0 : ( line.compare(len - sizeof(last_tag) + 1, 24, last_tag, 24) != 0 )
1510 0 : );
1511 : }
1512 :
1513 : bool
1514 0 : OksFile::compare(const char * file1_name, const char * file2_name)
1515 : {
1516 0 : std::ifstream f1(file1_name);
1517 0 : std::ifstream f2(file2_name);
1518 :
1519 0 : if (!f1)
1520 : {
1521 0 : throw oks::FileCompareError(file1_name, file2_name, "cannot open file");
1522 : }
1523 :
1524 0 : if (!f2)
1525 : {
1526 0 : throw oks::FileCompareError(file2_name, file1_name, "cannot open file");
1527 : }
1528 :
1529 0 : std::string line1;
1530 0 : std::string line2;
1531 :
1532 0 : while (true)
1533 : {
1534 0 : if (f1.eof() && f2.eof())
1535 : {
1536 : return true;
1537 : }
1538 :
1539 0 : std::getline(f1, line1);
1540 0 : std::getline(f2, line2);
1541 :
1542 0 : if ((line1 != line2) && (is_not_info(line1) || is_not_info(line2)))
1543 : {
1544 : return false;
1545 : }
1546 : }
1547 :
1548 : return true;
1549 0 : }
1550 :
1551 : } // namespace oks
1552 : } // namespace dunedaq
|