1 /*
2 Copyright (C) 2010 Andrew Caudwell (acaudwell@gmail.com)
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version
7 3 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "gource_settings.h"
19 #include "core/sdlapp.h"
20
21 #include <boost/filesystem.hpp>
22 #include <boost/format.hpp>
23 #include <boost/algorithm/string.hpp>
24
25 #include "core/utf8/utf8.h"
26 #include <time.h>
27
28 #include "formats/hg.h"
29 #include "formats/git.h"
30 #include "formats/bzr.h"
31 #include "formats/cvs-exp.h"
32 #include "formats/cvs2cl.h"
33 #include "formats/svn.h"
34
35 #ifndef GOURCE_FONT_FILE
36 #define GOURCE_FONT_FILE "FreeSans.ttf"
37 #endif
38
39 GourceSettings gGourceSettings;
40
41 //display help message
help(bool extended_help)42 void GourceSettings::help(bool extended_help) {
43
44 #ifdef _WIN32
45 //resize window to fit help message
46 SDLApp::resizeConsole(1000);
47 SDLApp::showConsole(true);
48 #endif
49
50 printf("Gource v%s\n", GOURCE_VERSION);
51
52 printf("Usage: gource [options] [path]\n");
53 printf("\nOptions:\n");
54 printf(" -h, --help Help\n\n");
55 printf(" -WIDTHxHEIGHT, --viewport Set viewport size\n");
56 printf(" -f, --fullscreen Fullscreen\n");
57 printf(" --screen SCREEN Screen number\n");
58 printf(" --multi-sampling Enable multi-sampling\n");
59 printf(" --no-vsync Disable vsync\n\n");
60
61 printf(" --start-date 'YYYY-MM-DD hh:mm:ss +tz' Start at a date and optional time\n");
62 printf(" --stop-date 'YYYY-MM-DD hh:mm:ss +tz' Stop at a date and optional time\n\n");
63 printf(" -p, --start-position POSITION Start at some position (0.0-1.0 or 'random')\n");
64 printf(" --stop-position POSITION Stop at some position\n");
65 printf(" -t, --stop-at-time SECONDS Stop after a specified number of seconds\n");
66 printf(" --stop-at-end Stop at end of the log\n");
67 printf(" --dont-stop Keep running after the end of the log\n");
68 printf(" --loop Loop at the end of the log\n\n");
69
70 printf(" -a, --auto-skip-seconds SECONDS Auto skip to next entry if nothing happens\n");
71 printf(" for a number of seconds (default: 3)\n");
72 printf(" --disable-auto-skip Disable auto skip\n");
73 printf(" -s, --seconds-per-day SECONDS Speed in seconds per day (default: 10)\n");
74 printf(" --realtime Realtime playback speed\n");
75 printf(" --no-time-travel Use the time of the last commit if the\n");
76 printf(" time of a commit is in the past\n");
77 printf(" -c, --time-scale SCALE Change simulation time scale (default: 1.0)\n");
78 printf(" -e, --elasticity FLOAT Elasticity of nodes (default: 0.0)\n\n");
79
80 printf(" --key Show file extension key\n\n");
81
82 printf(" --user-image-dir DIRECTORY Dir containing images to use as avatars\n");
83 printf(" --default-user-image IMAGE Default user image file\n");
84 printf(" --colour-images Colourize user images\n\n");
85
86 printf(" -i, --file-idle-time SECONDS Time files remain idle (default: 0)\n\n");
87
88 printf(" --max-files NUMBER Max number of files or 0 for no limit\n");
89 printf(" --max-file-lag SECONDS Max time files of a commit can take to appear\n\n");
90
91 printf(" --log-command VCS Show the VCS log command (git,svn,hg,bzr,cvs2cl)\n");
92 printf(" --log-format VCS Specify the log format (git,svn,hg,bzr,cvs2cl,custom)\n\n");
93
94 printf(" --load-config CONF_FILE Load a config file\n");
95 printf(" --save-config CONF_FILE Save a config file with the current options\n\n");
96
97 printf(" -o, --output-ppm-stream FILE Output PPM stream to a file ('-' for STDOUT)\n");
98 printf(" -r, --output-framerate FPS Framerate of output (25,30,60)\n\n");
99
100 if(extended_help) {
101 printf("Extended Options:\n\n");
102
103 printf(" --window-position XxY Initial window position\n");
104 printf(" --frameless Frameless window\n\n");
105
106 printf(" --output-custom-log FILE Output a custom format log file ('-' for STDOUT).\n\n");
107
108 printf(" -b, --background-colour FFFFFF Background colour in hex\n");
109 printf(" --background-image IMAGE Set a background image\n\n");
110
111 printf(" --bloom-multiplier Adjust the amount of bloom (default: 1.0)\n");
112 printf(" --bloom-intensity Adjust the intensity of the bloom (default: 0.75)\n\n");
113
114 printf(" --camera-mode MODE Camera mode (overview,track)\n");
115 printf(" --crop AXIS Crop view on an axis (vertical,horizontal)\n");
116 printf(" --padding FLOAT Camera view padding (default: 1.1)\n\n");
117
118 printf(" --disable-auto-rotate Disable automatic camera rotation\n\n");
119
120 printf(" --disable-input Disable keyboard and mouse input\n\n");
121
122 printf(" --date-format FORMAT Specify display date string (strftime format)\n\n");
123
124 printf(" --font-file FILE Specify the font\n");
125 printf(" --font-scale SCALE Scale the size of all fonts\n");
126 printf(" --font-size SIZE Font size used by date and title\n");
127 printf(" --file-font-size SIZE Font size for filenames\n");
128 printf(" --dir-font-size SIZE Font size for directory names\n");
129 printf(" --user-font-size SIZE Font size for user names\n");
130 printf(" --font-colour FFFFFF Font colour used by date and title in hex\n\n");
131
132 printf(" --file-extensions Show filename extensions only\n");
133 printf(" --file-extension-fallback Use filename as extension if the extension\n");
134 printf(" is missing or empty\n\n");
135
136 printf(" --git-branch Get the git log of a particular branch\n\n");
137
138 printf(" --hide DISPLAY_ELEMENT bloom,date,dirnames,files,filenames,mouse,progress,\n");
139 printf(" root,tree,users,usernames\n\n");
140
141 printf(" --logo IMAGE Logo to display in the foreground\n");
142 printf(" --logo-offset XxY Offset position of the logo\n\n");
143
144 printf(" --loop-delay-seconds SECONDS Seconds to delay before looping (default: 3)\n\n");
145
146 printf(" --title TITLE Set a title\n\n");
147
148 printf(" --transparent Make the background transparent\n\n");
149
150 printf(" --user-filter REGEX Ignore usernames matching this regex\n");
151 printf(" --user-show-filter REGEX Show only usernames matching this regex\n\n");
152 printf(" --file-filter REGEX Ignore file paths matching this regex\n");
153 printf(" --file-show-filter REGEX Show only file paths matching this regex\n\n");
154
155 printf(" --user-friction SECONDS Change the rate users slow down (default: 0.67)\n");
156 printf(" --user-scale SCALE Change scale of users (default: 1.0)\n");
157 printf(" --max-user-speed UNITS Speed users can travel per second (default: 500)\n\n");
158
159 printf(" --follow-user USER Camera will automatically follow this user\n");
160 printf(" --highlight-dirs Highlight the names of all directories\n");
161 printf(" --highlight-user USER Highlight the names of a particular user\n");
162 printf(" --highlight-users Highlight the names of all users\n\n");
163
164 printf(" --highlight-colour Font colour for highlighted users in hex.\n");
165 printf(" --selection-colour Font colour for selected users and files.\n");
166 printf(" --filename-colour Font colour for filenames.\n");
167 printf(" --dir-colour Font colour for directories.\n\n");
168
169 printf(" --dir-name-depth DEPTH Draw names of directories down to a specific depth.\n");
170 printf(" --dir-name-position FLOAT Position along edge of the directory name\n");
171 printf(" (between 0.0 and 1.0, default is 0.5).\n\n");
172
173 printf(" --filename-time SECONDS Duration to keep filenames on screen (default: 4.0)\n\n");
174
175 printf(" --caption-file FILE Caption file\n");
176 printf(" --caption-size SIZE Caption font size\n");
177 printf(" --caption-colour FFFFFF Caption colour in hex\n");
178 printf(" --caption-duration SECONDS Caption duration (default: 10.0)\n");
179 printf(" --caption-offset X Caption horizontal offset\n\n");
180
181 printf(" --hash-seed SEED Change the seed of hash function.\n\n");
182
183 printf(" --path PATH\n\n");
184 }
185
186 printf("PATH may be a supported version control directory, a log file, a gource config\n");
187 printf("file, or '-' to read STDIN. If omitted, gource will attempt to generate a log\n");
188 printf("from the current directory.\n\n");
189
190 if(!extended_help) {
191 printf("To see the full command line options use '-H'\n\n");
192 }
193
194 #ifdef _WIN32
195 if(!SDLApp::existing_console) {
196 printf("Press Enter\n");
197 getchar();
198 }
199 #endif
200
201 exit(0);
202 }
203
GourceSettings()204 GourceSettings::GourceSettings() {
205 repo_count = 0;
206 file_graphic = 0;
207 log_level = LOG_LEVEL_OFF;
208 shutdown = false;
209
210 setGourceDefaults();
211
212 default_section_name = "gource";
213
214 //translate args
215 arg_aliases["p"] = "start-position";
216 arg_aliases["a"] = "auto-skip-seconds";
217 arg_aliases["s"] = "seconds-per-day";
218 arg_aliases["t"] = "stop-at-time";
219 arg_aliases["i"] = "file-idle-time";
220 arg_aliases["e"] = "elasticity";
221 arg_aliases["h"] = "help";
222 arg_aliases["?"] = "help";
223 arg_aliases["H"] = "extended-help";
224 arg_aliases["b"] = "background-colour";
225 arg_aliases["c"] = "time-scale";
226 arg_aliases["background"] = "background-colour";
227 arg_aliases["disable-bloom"] = "hide-bloom";
228 arg_aliases["disable-progress"] = "hide-progress";
229 arg_aliases["highlight-all-users"] = "highlight-users";
230
231 //command line only options
232 conf_sections["help"] = "command-line";
233 conf_sections["extended-help"] = "command-line";
234 conf_sections["log-command"] = "command-line";
235 conf_sections["git-log-command"] = "command-line";
236 conf_sections["cvs-exp-command"] = "command-line";
237 conf_sections["cvs2cl-command"] = "command-line";
238 conf_sections["hg-log-command"] = "command-line";
239 conf_sections["bzr-log-command"] = "command-line";
240 conf_sections["svn-log-command"] = "command-line";
241 conf_sections["load-config"] = "command-line";
242 conf_sections["save-config"] = "command-line";
243 conf_sections["output-custom-log"] = "command-line";
244 conf_sections["log-level"] = "command-line";
245
246 //boolean args
247 arg_types["help"] = "bool";
248 arg_types["extended-help"] = "bool";
249 arg_types["stop-on-idle"] = "bool";
250 arg_types["stop-at-end"] = "bool";
251 arg_types["dont-stop"] = "bool";
252 arg_types["loop"] = "bool";
253 arg_types["realtime"] = "bool";
254 arg_types["no-time-travel"] = "bool";
255 arg_types["colour-images"] = "bool";
256 arg_types["hide-date"] = "bool";
257 arg_types["hide-files"] = "bool";
258 arg_types["hide-users"] = "bool";
259 arg_types["hide-tree"] = "bool";
260 arg_types["hide-usernames"] = "bool";
261 arg_types["hide-filenames"] = "bool";
262 arg_types["hide-dirnames"] = "bool";
263 arg_types["hide-progress"] = "bool";
264 arg_types["hide-bloom"] = "bool";
265 arg_types["hide-mouse"] = "bool";
266 arg_types["hide-root"] = "bool";
267 arg_types["highlight-users"] = "bool";
268 arg_types["highlight-dirs"] = "bool";
269 arg_types["file-extensions"] = "bool";
270 arg_types["file-extension-fallback"] = "bool";
271 arg_types["key"] = "bool";
272 arg_types["ffp"] = "bool";
273
274 arg_types["disable-auto-rotate"] = "bool";
275 arg_types["disable-auto-skip"] = "bool";
276 arg_types["disable-input"] = "bool";
277
278 arg_types["git-log-command"]= "bool";
279 arg_types["cvs-exp-command"]= "bool";
280 arg_types["cvs2cl-command"] = "bool";
281 arg_types["svn-log-command"]= "bool";
282 arg_types["hg-log-command"] = "bool";
283 arg_types["bzr-log-command"]= "bool";
284
285 arg_types["bloom-intensity"] = "float";
286 arg_types["bloom-multiplier"] = "float";
287 arg_types["elasticity"] = "float";
288 arg_types["seconds-per-day"] = "float";
289 arg_types["auto-skip-seconds"] = "float";
290 arg_types["stop-at-time"] = "float";
291 arg_types["max-user-speed"] = "float";
292 arg_types["user-friction"] = "float";
293 arg_types["padding"] = "float";
294 arg_types["time-scale"] = "float";
295 arg_types["dir-name-position"] = "float";
296 arg_types["loop-delay-seconds"] = "float";
297
298 arg_types["max-files"] = "int";
299 arg_types["font-size"] = "int";
300 arg_types["font-scale"] = "float";
301 arg_types["file-font-size"] = "int";
302 arg_types["dir-font-size"] = "int";
303 arg_types["user-font-size"] = "int";
304 arg_types["hash-seed"] = "int";
305
306 arg_types["user-filter"] = "multi-value";
307 arg_types["user-show-filter"] = "multi-value";
308 arg_types["file-filter"] = "multi-value";
309 arg_types["file-show-filter"] = "multi-value";
310 arg_types["follow-user"] = "multi-value";
311 arg_types["highlight-user"] = "multi-value";
312
313 arg_types["log-level"] = "string";
314 arg_types["background-image"] = "string";
315 arg_types["logo"] = "string";
316 arg_types["logo-offset"] = "string";
317 arg_types["log-command"] = "string";
318 arg_types["load-config"] = "string";
319 arg_types["save-config"] = "string";
320 arg_types["output-custom-log"] = "string";
321 arg_types["path"] = "string";
322 arg_types["log-command"] = "string";
323 arg_types["background-colour"] = "string";
324 arg_types["file-idle-time"] = "string";
325 arg_types["user-image-dir"] = "string";
326 arg_types["default-user-image"] = "string";
327 arg_types["date-format"] = "string";
328 arg_types["log-format"] = "string";
329 arg_types["git-branch"] = "string";
330 arg_types["start-position"] = "string";
331 arg_types["start-date"] = "string";
332 arg_types["stop-date"] = "string";
333 arg_types["stop-position"] = "string";
334 arg_types["crop"] = "string";
335 arg_types["hide"] = "string";
336 arg_types["max-file-lag"] = "string";
337 arg_types["user-scale"] = "string";
338 arg_types["camera-mode"] = "string";
339 arg_types["title"] = "string";
340 arg_types["font-file"] = "string";
341 arg_types["font-colour"] = "string";
342 arg_types["highlight-colour"] = "string";
343 arg_types["selection-colour"] = "string";
344 arg_types["dir-colour"] = "string";
345
346 arg_types["caption-file"] = "string";
347 arg_types["caption-size"] = "int";
348 arg_types["caption-duration"] = "float";
349 arg_types["caption-colour"] = "string";
350 arg_types["caption-offset"] = "int";
351
352 arg_types["filename-colour"] = "string";
353 arg_types["filename-time"] = "float";
354
355 arg_types["dir-name-depth"] = "int";
356 }
357
setGourceDefaults()358 void GourceSettings::setGourceDefaults() {
359
360 path = ".";
361 default_path = true;
362
363 ffp = false;
364
365 hide_date = false;
366 hide_users = false;
367 hide_tree = false;
368 hide_files = false;
369 hide_usernames = false;
370 hide_filenames = false;
371 hide_dirnames = false;
372 hide_progress = false;
373 hide_bloom = false;
374 hide_mouse = false;
375 hide_root = false;
376
377 start_timestamp = 0;
378 start_date = "";
379
380 stop_timestamp = 0;
381 stop_date = "";
382
383 start_position = 0.0f;
384 stop_position = 0.0f;
385 stop_at_time = -1.0f;
386 stop_on_idle = false;
387 stop_at_end = false;
388 dont_stop = false;
389 no_time_travel = false;
390
391 show_key = false;
392
393 disable_auto_rotate = false;
394
395 disable_input = false;
396
397 auto_skip_seconds = 3.0f;
398 days_per_second = 0.1f; // TODO: check this is right
399 file_idle_time = 0.0f;
400 time_scale = 1.0f;
401
402 loop = false;
403 loop_delay_seconds = 3.0f;
404
405 logo = "";
406 logo_offset = vec2(20.0f,20.0f);
407
408 colour_user_images = false;
409 default_user_image = "";
410 user_image_dir = "";
411 user_image_map.clear();
412
413 camera_zoom_min = 50.0f;
414 camera_zoom_default = 100.0f;
415 camera_zoom_max = 10000.0f;
416
417 camera_mode = "overview";
418 padding = 1.1f;
419
420 crop_vertical = false;
421 crop_horizontal = false;
422
423 bloom_multiplier = 1.0f;
424 bloom_intensity = 0.75f;
425
426 background_colour = vec3(0.1f, 0.1f, 0.1f);
427 background_image = "";
428
429 title = "";
430
431 font_file = GOURCE_FONT_FILE;
432 font_size = 16;
433 filename_font_size = 14;
434 dirname_font_size = 14;
435 user_font_size = 14;
436 dir_colour = vec3(1.0f);
437 font_colour = vec3(1.0f);
438 highlight_colour = vec3(1.0f);
439 selection_colour = vec3(1.0, 1.0, 0.3f);
440
441 dir_name_depth = 0;
442 dir_name_position = 0.5f;
443
444 elasticity = 0.0f;
445
446 git_branch = "";
447
448 log_format = "";
449 date_format = "%A, %d %B, %Y %X";
450
451 max_files = 0;
452 max_user_speed = 500.0f;
453 max_file_lag = 5.0f;
454
455 user_idle_time = 3.0f;
456 user_friction = 1.0f;
457 user_scale = 1.0f;
458
459 follow_users.clear();
460 highlight_users.clear();
461 highlight_all_users = false;
462 highlight_dirs = false;
463
464 caption_file = "";
465 caption_duration = 10.0f;
466 caption_size = 16;
467 caption_offset = 0;
468 caption_colour = vec3(1.0f, 1.0f, 1.0f);
469
470 filename_colour = vec3(1.0f, 1.0f, 1.0f);
471 filename_time = 4.0f;
472
473 gStringHashSeed = 31;
474
475 //delete file filters
476 for(std::vector<Regex*>::iterator it = file_filters.begin(); it != file_filters.end(); it++) {
477 delete (*it);
478 }
479 file_filters.clear();
480
481 //delete file whitelists
482 for(std::vector<Regex*>::iterator it = file_show_filters.begin(); it != file_show_filters.end(); it++) {
483 delete (*it);
484 }
485 file_show_filters.clear();
486
487 file_extensions = false;
488 file_extension_fallback = false;
489
490 //delete user filters
491 for(std::vector<Regex*>::iterator it = user_filters.begin(); it != user_filters.end(); it++) {
492 delete (*it);
493 }
494 user_filters.clear();
495
496 //delete user whitelist
497 for(std::vector<Regex*>::iterator it = user_show_filters.begin(); it != user_show_filters.end(); it++) {
498 delete (*it);
499 }
500 user_show_filters.clear();
501 }
502
commandLineOption(const std::string & name,const std::string & value)503 void GourceSettings::commandLineOption(const std::string& name, const std::string& value) {
504
505 if(name == "help") {
506 help();
507 }
508
509 if(name == "extended-help") {
510 help(true);
511 }
512
513 if(name == "load-config" && value.size() > 0) {
514 load_config = value;
515 return;
516 }
517
518 if(name == "save-config" && value.size() > 0) {
519 save_config = value;
520 return;
521 }
522
523 std::string log_command;
524
525 if(name == "log-command") {
526 log_command = value;
527 }
528
529 if(name == "git-log-command" || log_command == "git") {
530 SDLAppInfo(GitCommitLog::logCommand());
531 }
532
533 if(name == "cvs-exp-command" || log_command == "cvs-exp") {
534 SDLAppInfo(CVSEXPCommitLog::logCommand());
535 }
536
537 if(log_command == "cvs") {
538 throw ConfFileException("please use either 'cvs2cl' or 'cvs-exp'", "", 0);
539 }
540
541 if(name == "cvs2cl-command" || log_command == "cvs2cl") {
542 SDLAppInfo(CVS2CLCommitLog::logCommand());
543 }
544
545 if(name == "svn-log-command" || log_command == "svn") {
546 SDLAppInfo(SVNCommitLog::logCommand());
547 }
548
549 if(name == "hg-log-command" || log_command == "hg") {
550 SDLAppInfo(MercurialLog::logCommand());
551 }
552
553 if(name == "bzr-log-command" || log_command == "bzr") {
554 SDLAppInfo(BazaarLog::logCommand());
555 }
556
557 if(name == "output-custom-log" && value.size() > 0) {
558 output_custom_filename = value;
559 return;
560 }
561
562 if(name == "log-level") {
563 if(value == "warn") {
564 log_level = LOG_LEVEL_WARN;
565 } else if(value == "debug") {
566 log_level = LOG_LEVEL_DEBUG;
567 } else if(value == "info") {
568 log_level = LOG_LEVEL_INFO;
569 } else if(value == "error") {
570 log_level = LOG_LEVEL_ERROR;
571 } else if(value == "pedantic") {
572 log_level = LOG_LEVEL_PEDANTIC;
573 }
574 return;
575 }
576
577 std::string invalid_error = std::string("invalid ") + name + std::string(" value");
578 throw ConfFileException(invalid_error, "", 0);
579 }
580
581
582 #ifdef __APPLE__
583 #include <CoreFoundation/CoreFoundation.h>
584 #endif
importGourceSettings(ConfFile & conffile,ConfSection * gource_settings)585 void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gource_settings) {
586
587 setGourceDefaults();
588
589 if(gource_settings == 0) gource_settings = conffile.getSection(default_section_name);
590
591 if(gource_settings == 0) {
592 gource_settings = conffile.addSection("gource");
593 }
594
595 ConfEntry* entry = 0;
596
597 //hide flags
598
599 std::vector<std::string> hide_fields;
600
601 if((entry = gource_settings->getEntry("hide")) != 0) {
602
603 if(!entry->hasValue()) conffile.missingValueException(entry);
604
605 std::string hide_string = entry->getString();
606
607 size_t sep;
608 while((sep = hide_string.find(",")) != std::string::npos) {
609
610 if(sep == 0 && hide_string.size()==1) break;
611
612 if(sep == 0) {
613 hide_string = hide_string.substr(sep+1, hide_string.size()-1);
614 continue;
615 }
616
617 std::string hide_field = hide_string.substr(0, sep);
618 hide_fields.push_back(hide_field);
619 hide_string = hide_string.substr(sep+1, hide_string.size()-1);
620 }
621
622 if(hide_string.size() > 0 && hide_string != ",") hide_fields.push_back(hide_string);
623
624 //validate field list
625
626 for(std::vector<std::string>::iterator it = hide_fields.begin(); it != hide_fields.end(); it++) {
627 std::string hide_field = (*it);
628
629 if( hide_field != "date"
630 && hide_field != "users"
631 && hide_field != "tree"
632 && hide_field != "files"
633 && hide_field != "usernames"
634 && hide_field != "filenames"
635 && hide_field != "dirnames"
636 && hide_field != "bloom"
637 && hide_field != "progress"
638 && hide_field != "mouse"
639 && hide_field != "root") {
640 std::string unknown_hide_option = std::string("unknown option hide ") + hide_field;
641 conffile.entryException(entry, unknown_hide_option);
642 }
643 }
644 }
645
646 //check hide booleans
647 for(std::map<std::string,std::string>::iterator it = arg_types.begin(); it != arg_types.end(); it++) {
648 if(it->first.find("hide-") == 0 && it->second == "bool") {
649
650 if(gource_settings->getBool(it->first)) {
651 std::string hide_field = it->first.substr(5, it->first.size()-5);
652 hide_fields.push_back(hide_field);
653 }
654 }
655 }
656
657 if(hide_fields.size()>0) {
658
659 for(std::vector<std::string>::iterator it = hide_fields.begin(); it != hide_fields.end(); it++) {
660 std::string hidestr = (*it);
661
662 if(hidestr == "date") hide_date = true;
663 else if(hidestr == "users") hide_users = true;
664 else if(hidestr == "tree") hide_tree = true;
665 else if(hidestr == "files") hide_files = true;
666 else if(hidestr == "usernames") hide_usernames = true;
667 else if(hidestr == "filenames") hide_filenames = true;
668 else if(hidestr == "dirnames") hide_dirnames = true;
669 else if(hidestr == "bloom") hide_bloom = true;
670 else if(hidestr == "progress") hide_progress = true;
671 else if(hidestr == "root") hide_root = true;
672 else if(hidestr == "mouse") {
673 hide_mouse = true;
674 hide_progress = true;
675 }
676 }
677 }
678
679 if((entry = gource_settings->getEntry("date-format")) != 0) {
680
681 if(!entry->hasValue()) conffile.missingValueException(entry);
682
683 date_format = entry->getString();
684 }
685
686 if(gource_settings->getBool("disable-auto-rotate")) {
687 disable_auto_rotate=true;
688 }
689
690 if(gource_settings->getBool("disable-auto-skip")) {
691 auto_skip_seconds = -1.0;
692 }
693
694 if(gource_settings->getBool("disable-input")) {
695 disable_input=true;
696 }
697
698 if(gource_settings->getBool("loop")) {
699 loop = true;
700 }
701
702 if((entry = gource_settings->getEntry("loop-delay-seconds")) != 0) {
703
704 if(!entry->hasValue()) conffile.entryException(entry, "specify loop-delay-seconds (float)");
705
706 loop_delay_seconds = entry->getFloat();
707
708 if(loop_delay_seconds<=0.0f) {
709 conffile.invalidValueException(entry);
710 }
711 }
712
713 if((entry = gource_settings->getEntry("git-branch")) != 0) {
714
715 if(!entry->hasValue()) conffile.missingValueException(entry);
716
717 Regex branch_regex("^(?!-)[/\\w.,;_=+{}\\[\\]-]+$");
718
719 std::string branch = entry->getString();
720
721 if(branch_regex.match(branch)) {
722 git_branch = branch;
723 } else {
724 conffile.invalidValueException(entry);
725 }
726 }
727
728 if(gource_settings->getBool("colour-images")) {
729 colour_user_images = true;
730 }
731
732 if((entry = gource_settings->getEntry("crop")) != 0) {
733
734 if(!entry->hasValue()) conffile.entryException(entry, "specify crop (vertical,horizontal)");
735
736 std::string crop = entry->getString();
737
738 if(crop == "vertical") {
739 crop_vertical = true;
740 } else if (crop == "horizontal") {
741 crop_horizontal = true;
742 } else {
743 conffile.invalidValueException(entry);
744 }
745 }
746
747 if((entry = gource_settings->getEntry("log-format")) != 0) {
748
749 if(!entry->hasValue()) conffile.entryException(entry, "specify log-format (format)");
750
751 log_format = entry->getString();
752
753 if(log_format == "cvs") {
754 conffile.entryException(entry, "please use either 'cvs2cl' or 'cvs-exp'");
755 }
756
757 if( log_format != "git"
758 && log_format != "cvs-exp"
759 && log_format != "cvs2cl"
760 && log_format != "svn"
761 && log_format != "custom"
762 && log_format != "hg"
763 && log_format != "bzr"
764 && log_format != "apache") {
765
766 conffile.invalidValueException(entry);
767 }
768 }
769
770 if((entry = gource_settings->getEntry("default-user-image")) != 0) {
771
772 if(!entry->hasValue()) conffile.entryException(entry, "specify default-user-image (image path)");
773
774 default_user_image = entry->getString();
775 }
776
777 if((entry = gource_settings->getEntry("user-image-dir")) != 0) {
778
779 if(!entry->hasValue()) conffile.entryException(entry, "specify user-image-dir (directory)");
780
781 user_image_dir = entry->getString();
782
783 //append slash
784 if(user_image_dir[user_image_dir.size()-1] != '/') {
785 user_image_dir += std::string("/");
786 }
787
788 user_image_map.clear();
789
790 boost::filesystem::path image_dir_path(user_image_dir);
791
792 if(!is_directory(image_dir_path)) {
793 conffile.entryException(entry, "specified user-image-dir is not a directory");
794 }
795
796 std::vector<boost::filesystem::path> image_dir_files;
797
798 try {
799 copy(boost::filesystem::directory_iterator(image_dir_path), boost::filesystem::directory_iterator(), back_inserter(image_dir_files));
800 } catch(const boost::filesystem::filesystem_error& exception) {
801 conffile.entryException(entry, "error reading specified user-image-dir");
802 }
803
804 for(boost::filesystem::path& p : image_dir_files) {
805
806 std::string dirfile;
807
808 #ifdef _WIN32
809 std::wstring dirfile_16 = p.filename().wstring();
810 utf8::utf16to8(dirfile_16.begin(), dirfile_16.end(), back_inserter(dirfile));
811 #else
812 dirfile = p.filename().string();
813 #endif
814 std::string file_ext = extension(p);
815 boost::algorithm::to_lower(file_ext);
816
817 if(file_ext != ".jpg" && file_ext != ".jpeg" && file_ext != ".png") continue;
818
819 std::string image_path = gGourceSettings.user_image_dir + dirfile;
820 std::string name = dirfile.substr(0,dirfile.size() - file_ext.size());
821
822 #ifdef __APPLE__
823 CFMutableStringRef help = CFStringCreateMutable(kCFAllocatorDefault, 0);
824 CFStringAppendCString(help, name.c_str(), kCFStringEncodingUTF8);
825 CFStringNormalize(help, kCFStringNormalizationFormC);
826 char data[4096];
827 CFStringGetCString(help,
828 data,
829 sizeof(data),
830 kCFStringEncodingUTF8);
831 name = data;
832 #endif
833
834 debugLog("%s => %s", name.c_str(), image_path.c_str());
835
836 user_image_map[name] = image_path;
837 }
838 }
839
840 if((entry = gource_settings->getEntry("caption-file")) != 0) {
841
842 if(!entry->hasValue()) conffile.entryException(entry, "specify caption file (filename)");
843
844 caption_file = entry->getString();
845
846 if(!boost::filesystem::exists(caption_file)) {
847 conffile.entryException(entry, "caption file not found");
848 }
849 }
850
851 if((entry = gource_settings->getEntry("caption-duration")) != 0) {
852
853 if(!entry->hasValue()) conffile.entryException(entry, "specify caption duration (seconds)");
854
855 caption_duration = entry->getFloat();
856
857 if(caption_duration <= 0.0f) {
858 conffile.invalidValueException(entry);
859 }
860 }
861
862 if((entry = gource_settings->getEntry("caption-size")) != 0) {
863
864 if(!entry->hasValue()) conffile.entryException(entry, "specify caption size");
865
866 caption_size = entry->getInt();
867
868 if(caption_size<1 || caption_size>100) {
869 conffile.invalidValueException(entry);
870 }
871 }
872
873 if((entry = gource_settings->getEntry("caption-offset")) != 0) {
874
875 if(!entry->hasValue()) conffile.entryException(entry, "specify caption offset");
876
877 caption_offset = entry->getInt();
878 }
879
880 if((entry = gource_settings->getEntry("caption-colour")) != 0) {
881
882 if(!entry->hasValue()) conffile.entryException(entry, "specify caption colour (FFFFFF)");
883
884 int r,g,b;
885
886 std::string colstring = entry->getString();
887
888 if(entry->isVec3()) {
889 caption_colour = entry->getVec3();
890 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
891 caption_colour = vec3(r,g,b);
892 caption_colour /= 255.0f;
893 } else {
894 conffile.invalidValueException(entry);
895 }
896 }
897
898 if((entry = gource_settings->getEntry("filename-colour")) != 0) {
899 if(!entry->hasValue()) conffile.entryException(entry, "specify filename colour (FFFFFF)");
900
901 int r,g,b;
902
903 std::string colstring = entry->getString();
904
905 if(entry->isVec3()) {
906 filename_colour = entry->getVec3();
907 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
908 filename_colour = vec3(r,g,b);
909 filename_colour /= 255.0f;
910 } else {
911 conffile.invalidValueException(entry);
912 }
913 }
914
915 if((entry = gource_settings->getEntry("filename-time")) != 0) {
916
917 if(!entry->hasValue()) conffile.entryException(entry, "specify duration to keep files on screen (float)");
918
919 filename_time = entry->getFloat();
920
921 if(filename_time<2.0f) {
922 conffile.entryException(entry, "filename-time must be >= 2.0");
923 }
924 }
925
926 if((entry = gource_settings->getEntry("bloom-intensity")) != 0) {
927
928 if(!entry->hasValue()) conffile.entryException(entry, "specify bloom-intensity (float)");
929
930 bloom_intensity = entry->getFloat();
931
932 if(bloom_intensity<=0.0f) {
933 conffile.invalidValueException(entry);
934 }
935 }
936
937 if((entry = gource_settings->getEntry("bloom-multiplier")) != 0) {
938
939 if(!entry->hasValue()) conffile.entryException(entry, "specify bloom-multiplier (float)");
940
941 bloom_multiplier = entry->getFloat();
942
943 if(bloom_multiplier<=0.0f) {
944 conffile.invalidValueException(entry);
945 }
946 }
947
948 if((entry = gource_settings->getEntry("elasticity")) != 0) {
949
950 if(!entry->hasValue()) conffile.entryException(entry, "specify elasticity (float)");
951
952 elasticity = entry->getFloat();
953
954 if(elasticity<=0.0f) {
955 conffile.invalidValueException(entry);
956 }
957 }
958
959 if((entry = gource_settings->getEntry("font-file")) != 0) {
960
961 if(!entry->hasValue()) conffile.entryException(entry, "specify font file");
962
963 font_file = entry->getString();
964
965 boost::filesystem::path font_file_path(font_file);
966
967 if(!boost::filesystem::exists(font_file_path)) {
968 conffile.invalidValueException(entry);
969 }
970
971 font_file = boost::filesystem::canonical(font_file_path).string();
972
973 if(font_file.empty()) {
974 conffile.invalidValueException(entry);
975 }
976 }
977
978 if((entry = gource_settings->getEntry("font-size")) != 0) {
979
980 if(!entry->hasValue()) conffile.entryException(entry, "specify font size");
981
982 font_size = entry->getInt();
983
984 if(font_size<1 || font_size>100) {
985 conffile.invalidValueException(entry);
986 }
987 }
988
989 if((entry = gource_settings->getEntry("file-font-size")) != 0) {
990
991 if(!entry->hasValue()) conffile.entryException(entry, "specify font size");
992
993 filename_font_size = entry->getInt();
994
995 if(filename_font_size<1 || filename_font_size>100) {
996 conffile.invalidValueException(entry);
997 }
998 }
999
1000 if((entry = gource_settings->getEntry("dir-font-size")) != 0) {
1001
1002 if(!entry->hasValue()) conffile.entryException(entry, "specify font size");
1003
1004 dirname_font_size = entry->getInt();
1005
1006 if(dirname_font_size<1 || dirname_font_size>100) {
1007 conffile.invalidValueException(entry);
1008 }
1009 }
1010
1011 if((entry = gource_settings->getEntry("user-font-size")) != 0) {
1012
1013 if(!entry->hasValue()) conffile.entryException(entry, "specify font size");
1014
1015 user_font_size = entry->getInt();
1016
1017 if(user_font_size<1 || user_font_size>100) {
1018 conffile.invalidValueException(entry);
1019 }
1020 }
1021
1022 if((entry = gource_settings->getEntry("font-scale")) != 0) {
1023
1024 if(!entry->hasValue()) conffile.entryException(entry, "specify font scale");
1025
1026 float font_scale = entry->getFloat();
1027
1028 if(font_scale<0.0f || font_scale>10.0f) {
1029 conffile.invalidValueException(entry);
1030 }
1031
1032 font_size = glm::clamp((int)(font_size * font_scale), 1, 100);
1033 user_font_size = glm::clamp((int)(user_font_size * font_scale), 1, 100);
1034 dirname_font_size = glm::clamp((int)(dirname_font_size * font_scale), 1, 100);
1035 }
1036
1037 if((entry = gource_settings->getEntry("hash-seed")) != 0) {
1038
1039 if(!entry->hasValue()) conffile.entryException(entry, "specify hash seed (integer)");
1040
1041 gStringHashSeed = entry->getInt();
1042 }
1043
1044 if((entry = gource_settings->getEntry("font-colour")) != 0) {
1045
1046 if(!entry->hasValue()) conffile.entryException(entry, "specify font colour (FFFFFF)");
1047
1048 int r,g,b;
1049
1050 std::string colstring = entry->getString();
1051
1052 if(entry->isVec3()) {
1053 font_colour = entry->getVec3();
1054 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
1055 font_colour = vec3(r,g,b);
1056 font_colour /= 255.0f;
1057 } else {
1058 conffile.invalidValueException(entry);
1059 }
1060 }
1061
1062 if((entry = gource_settings->getEntry("background-colour")) != 0) {
1063
1064 if(!entry->hasValue()) conffile.entryException(entry, "specify background colour (FFFFFF)");
1065
1066 int r,g,b;
1067
1068 std::string colstring = entry->getString();
1069
1070 if(entry->isVec3()) {
1071 background_colour = entry->getVec3();
1072 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
1073 background_colour = vec3(r,g,b);
1074 background_colour /= 255.0f;
1075 } else {
1076 conffile.invalidValueException(entry);
1077 }
1078 }
1079
1080 if((entry = gource_settings->getEntry("highlight-colour")) != 0) {
1081
1082 if(!entry->hasValue()) conffile.entryException(entry, "specify highlight colour (FFFFFF)");
1083
1084 int r,g,b;
1085
1086 std::string colstring = entry->getString();
1087
1088 if(entry->isVec3()) {
1089 highlight_colour = entry->getVec3();
1090 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
1091 highlight_colour = vec3(r,g,b);
1092 highlight_colour /= 255.0f;
1093 } else {
1094 conffile.invalidValueException(entry);
1095 }
1096 }
1097
1098 if((entry = gource_settings->getEntry("selection-colour")) != 0) {
1099
1100 if(!entry->hasValue()) conffile.entryException(entry, "specify selection colour (FFFFFF)");
1101
1102 int r,g,b;
1103
1104 std::string colstring = entry->getString();
1105
1106 if(entry->isVec3()) {
1107 selection_colour = entry->getVec3();
1108 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
1109 selection_colour = vec3(r,g,b);
1110 selection_colour /= 255.0f;
1111 } else {
1112 conffile.invalidValueException(entry);
1113 }
1114 }
1115
1116 if((entry = gource_settings->getEntry("dir-colour")) != 0) {
1117
1118 if(!entry->hasValue()) conffile.entryException(entry, "specify dir colour (FFFFFF)");
1119
1120 int r,g,b;
1121
1122 std::string colstring = entry->getString();
1123
1124 if(entry->isVec3()) {
1125 dir_colour = entry->getVec3();
1126 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
1127 dir_colour = vec3(r,g,b);
1128 dir_colour /= 255.0f;
1129 } else {
1130 conffile.invalidValueException(entry);
1131 }
1132 }
1133
1134 if((entry = gource_settings->getEntry("background-image")) != 0) {
1135
1136 if(!entry->hasValue()) conffile.entryException(entry, "specify background image (image path)");
1137
1138 background_image = entry->getString();
1139 }
1140
1141 if((entry = gource_settings->getEntry("title")) != 0) {
1142
1143 if(!entry->hasValue()) conffile.entryException(entry, "specify title");
1144
1145 title = entry->getString();
1146 }
1147
1148 if((entry = gource_settings->getEntry("logo")) != 0) {
1149
1150 if(!entry->hasValue()) conffile.entryException(entry, "specify logo (image path)");
1151
1152 logo = entry->getString();
1153 }
1154
1155 if((entry = gource_settings->getEntry("logo-offset")) != 0) {
1156
1157 if(!entry->hasValue()) conffile.entryException(entry, "specify logo-offset (XxY)");
1158
1159 std::string logo_offset_str = entry->getString();
1160
1161 int posx = 0;
1162 int posy = 0;
1163
1164 if(parseRectangle(logo_offset_str, posx, posy)) {
1165 logo_offset = vec2(posx, posy);
1166 } else {
1167 conffile.invalidValueException(entry);
1168 }
1169
1170 }
1171
1172 if((entry = gource_settings->getEntry("seconds-per-day")) != 0) {
1173
1174 if(!entry->hasValue()) conffile.entryException(entry, "specify seconds-per-day (seconds)");
1175
1176 float seconds_per_day = entry->getFloat();
1177
1178 if(seconds_per_day<=0.0f) {
1179 conffile.invalidValueException(entry);
1180 }
1181
1182 // convert seconds-per-day to days-per-second
1183 days_per_second = 1.0 / seconds_per_day;
1184 }
1185
1186 if((entry = gource_settings->getEntry("auto-skip-seconds")) != 0) {
1187
1188 if(!entry->hasValue()) conffile.entryException(entry, "specify auto-skip-seconds (seconds)");
1189
1190 auto_skip_seconds = entry->getFloat();
1191
1192 if(auto_skip_seconds <= 0.0) {
1193 conffile.invalidValueException(entry);
1194 }
1195 }
1196
1197 if((entry = gource_settings->getEntry("file-idle-time")) != 0) {
1198
1199 if(!entry->hasValue()) conffile.entryException(entry, "specify file-idle-time (seconds)");
1200
1201 std::string file_idle_str = entry->getString();
1202
1203 file_idle_time = (float) atoi(file_idle_str.c_str());
1204
1205 if(file_idle_time<0.0f || (file_idle_time == 0.0f && file_idle_str[0] != '0') ) {
1206 conffile.invalidValueException(entry);
1207 }
1208 }
1209
1210 if((entry = gource_settings->getEntry("user-idle-time")) != 0) {
1211
1212 if(!entry->hasValue()) conffile.entryException(entry, "specify user-idle-time (seconds)");
1213
1214 user_idle_time = entry->getFloat();
1215
1216 if(user_idle_time < 0.0f) {
1217 conffile.invalidValueException(entry);
1218 }
1219 }
1220
1221 if((entry = gource_settings->getEntry("time-scale")) != 0) {
1222
1223 if(!entry->hasValue())
1224 conffile.entryException(entry, "specify time-scale (scale)");
1225
1226 time_scale = entry->getFloat();
1227
1228 if(time_scale <= 0.0f || time_scale > 4.0f) {
1229 conffile.entryException(entry, "time-scale outside of range 0.0 - 4.0");
1230 }
1231 }
1232
1233 if((entry = gource_settings->getEntry("start-date")) != 0) {
1234
1235 if(!entry->hasValue()) conffile.entryException(entry, "specify start-date (YYYY-MM-DD hh:mm:ss)");
1236
1237 std::string start_date_string = entry->getString();
1238
1239 if(parseDateTime(start_date_string, start_timestamp)) {
1240
1241 char datestr[256];
1242 strftime(datestr, 256, "%Y-%m-%d", localtime ( &start_timestamp ));
1243 start_date = datestr;
1244
1245 } else {
1246 conffile.invalidValueException(entry);
1247 }
1248 }
1249
1250 if((entry = gource_settings->getEntry("stop-date")) != 0) {
1251
1252 if(!entry->hasValue()) conffile.entryException(entry, "specify stop-date (YYYY-MM-DD hh:mm:ss)");
1253
1254 std::string end_date_string = entry->getString();
1255
1256 if(parseDateTime(end_date_string, stop_timestamp)) {
1257
1258 struct tm * timeinfo;
1259 timeinfo = localtime ( &stop_timestamp );
1260
1261 time_t stop_timestamp_rounded = stop_timestamp;
1262
1263 if(timeinfo->tm_hour > 0 || timeinfo->tm_min > 0 || timeinfo->tm_sec > 0) {
1264 stop_timestamp_rounded += 60*60*24;
1265 }
1266
1267 char datestr[256];
1268 strftime(datestr, 256, "%Y-%m-%d", localtime ( &stop_timestamp_rounded ));
1269 stop_date = datestr;
1270
1271 } else {
1272 conffile.invalidValueException(entry);
1273 }
1274 }
1275
1276 if((entry = gource_settings->getEntry("start-position")) != 0) {
1277
1278 if(!entry->hasValue()) conffile.entryException(entry, "specify start-position (float,random)");
1279
1280 if(entry->getString() == "random") {
1281 srand(time(0));
1282 start_position = (rand() % 1000) / 1000.0f;
1283 } else {
1284 start_position = entry->getFloat();
1285
1286 if(start_position<=0.0 || start_position>=1.0) {
1287 conffile.entryException(entry, "start-position outside of range 0.0 - 1.0 (non-inclusive)");
1288 }
1289 }
1290 }
1291
1292 if((entry = gource_settings->getEntry("stop-position")) != 0) {
1293
1294 if(!entry->hasValue()) conffile.entryException(entry, "specify stop-position (float)");
1295
1296 stop_position = entry->getFloat();
1297
1298 if(stop_position<=0.0 || stop_position>1.0) {
1299 conffile.entryException(entry, "stop-position outside of range 0.0 - 1.0 (inclusive)");
1300 }
1301 }
1302
1303 if((entry = gource_settings->getEntry("stop-at-time")) != 0) {
1304
1305 if(!entry->hasValue()) conffile.entryException(entry, "specify stop-at-time (seconds)");
1306
1307 stop_at_time = entry->getFloat();
1308
1309 if(stop_at_time <= 0.0) {
1310 conffile.invalidValueException(entry);
1311 }
1312 }
1313
1314 if(gource_settings->getBool("key")) {
1315 show_key = true;
1316 }
1317
1318 if(gource_settings->getBool("ffp")) {
1319 ffp = true;
1320 }
1321
1322 if(gource_settings->getBool("realtime")) {
1323 days_per_second = 1.0 / 86400.0;
1324 }
1325
1326 if(gource_settings->getBool("no-time-travel")) {
1327 no_time_travel = true;
1328 }
1329
1330 if(gource_settings->getBool("dont-stop")) {
1331 dont_stop = true;
1332 }
1333
1334 if(gource_settings->getBool("stop-at-end")) {
1335 stop_at_end = true;
1336 }
1337
1338 //NOTE: this no longer does anything
1339 if(gource_settings->getBool("stop-on-idle")) {
1340 stop_on_idle = true;
1341 }
1342
1343 if((entry = gource_settings->getEntry("max-files")) != 0) {
1344
1345 if(!entry->hasValue()) conffile.entryException(entry, "specify max-files (number)");
1346
1347 max_files = entry->getInt();
1348
1349 if( max_files<0 || (max_files == 0 && entry->getString() != "0") ) {
1350 conffile.invalidValueException(entry);
1351 }
1352 }
1353
1354 if((entry = gource_settings->getEntry("max-file-lag")) != 0) {
1355
1356 if(!entry->hasValue()) conffile.entryException(entry, "specify max-file-lag (seconds)");
1357
1358 max_file_lag = entry->getFloat();
1359
1360 if(max_file_lag==0.0) {
1361 conffile.invalidValueException(entry);
1362 }
1363 }
1364
1365 if((entry = gource_settings->getEntry("user-friction")) != 0) {
1366
1367 if(!entry->hasValue()) conffile.entryException(entry, "specify user-friction (seconds)");
1368
1369 user_friction = entry->getFloat();
1370
1371 if(user_friction<=0.0) {
1372 conffile.invalidValueException(entry);
1373 }
1374
1375 user_friction = 1.0 / user_friction;
1376 }
1377
1378 if((entry = gource_settings->getEntry("user-scale")) != 0) {
1379
1380 if(!entry->hasValue()) conffile.entryException(entry, "specify user-scale (scale)");
1381
1382 user_scale = entry->getFloat();
1383
1384 if(user_scale<=0.0 || user_scale>100.0) {
1385 conffile.invalidValueException(entry);
1386 }
1387 }
1388
1389 if((entry = gource_settings->getEntry("max-user-speed")) != 0) {
1390
1391 if(!entry->hasValue()) conffile.entryException(entry, "specify max-user-speed (units)");
1392
1393 max_user_speed = entry->getFloat();
1394
1395 if(max_user_speed<=0) {
1396 conffile.invalidValueException(entry);
1397 }
1398 }
1399
1400 if( gource_settings->getBool("highlight-users")
1401 || gource_settings->getBool("highlight-all-users")) {
1402 highlight_all_users = true;
1403 }
1404
1405 if(gource_settings->getBool("highlight-dirs")) {
1406 highlight_dirs = true;
1407 }
1408
1409 if((entry = gource_settings->getEntry("camera-mode")) != 0) {
1410
1411 if(!entry->hasValue()) conffile.entryException(entry, "specify camera-mode (overview,track)");
1412
1413 camera_mode = entry->getString();
1414
1415 if(camera_mode != "overview" && camera_mode != "track") {
1416 conffile.invalidValueException(entry);
1417 }
1418 }
1419
1420 if((entry = gource_settings->getEntry("padding")) != 0) {
1421
1422 if(!entry->hasValue()) conffile.entryException(entry, "specify padding (float)");
1423
1424 padding = entry->getFloat();
1425
1426 if(padding <= 0.0f || padding >= 2.0f) {
1427 conffile.invalidValueException(entry);
1428 }
1429 }
1430
1431 // multi-value entries
1432
1433 if((entry = gource_settings->getEntry("highlight-user")) != 0) {
1434
1435 ConfEntryList* highlight_user_entries = gource_settings->getEntries("highlight-user");
1436
1437 for(ConfEntryList::iterator it = highlight_user_entries->begin(); it != highlight_user_entries->end(); it++) {
1438
1439 entry = *it;
1440
1441 if(!entry->hasValue()) conffile.entryException(entry, "specify highlight-user (user)");
1442
1443 highlight_users.push_back(entry->getString());
1444 }
1445 }
1446
1447 if((entry = gource_settings->getEntry("follow-user")) != 0) {
1448
1449 ConfEntryList* follow_user_entries = gource_settings->getEntries("follow-user");
1450
1451 for(ConfEntryList::iterator it = follow_user_entries->begin(); it != follow_user_entries->end(); it++) {
1452
1453 entry = *it;
1454
1455 if(!entry->hasValue()) conffile.entryException(entry, "specify follow-user (user)");
1456
1457 follow_users.push_back(entry->getString());
1458 }
1459 }
1460
1461 if(gource_settings->getBool("file-extensions")) {
1462 file_extensions=true;
1463 }
1464
1465 if(gource_settings->getBool("file-extension-fallback")) {
1466 file_extension_fallback=true;
1467 }
1468
1469 if((entry = gource_settings->getEntry("file-filter")) != 0) {
1470
1471 ConfEntryList* filters = gource_settings->getEntries("file-filter");
1472
1473 for(ConfEntryList::iterator it = filters->begin(); it != filters->end(); it++) {
1474
1475 entry = *it;
1476
1477 if(!entry->hasValue()) conffile.entryException(entry, "specify file-filter (regex)");
1478
1479 std::string filter_string = entry->getString();
1480
1481 Regex* r = new Regex(filter_string, 1);
1482
1483 if(!r->isValid()) {
1484 delete r;
1485 conffile.entryException(entry, "invalid file-filter regular expression");
1486 }
1487
1488 file_filters.push_back(r);
1489 }
1490 }
1491
1492 if((entry = gource_settings->getEntry("file-show-filter")) != 0) {
1493
1494 ConfEntryList* filters = gource_settings->getEntries("file-show-filter");
1495
1496 for(ConfEntryList::iterator it = filters->begin(); it != filters->end(); it++) {
1497
1498 entry = *it;
1499
1500 if(!entry->hasValue()) conffile.entryException(entry, "specify file-show-filter (regex)");
1501
1502 std::string filter_string = entry->getString();
1503
1504 Regex* r = new Regex(filter_string, 1);
1505
1506 if(!r->isValid()) {
1507 delete r;
1508 conffile.entryException(entry, "invalid file-show-filter regular expression");
1509 }
1510
1511 file_show_filters.push_back(r);
1512 }
1513 }
1514
1515 if((entry = gource_settings->getEntry("user-filter")) != 0) {
1516
1517 ConfEntryList* filters = gource_settings->getEntries("user-filter");
1518
1519 for(ConfEntryList::iterator it = filters->begin(); it != filters->end(); it++) {
1520
1521 entry = *it;
1522
1523 if(!entry->hasValue()) conffile.entryException(entry, "specify user-filter (regex)");
1524
1525 std::string filter_string = entry->getString();
1526
1527 Regex* r = new Regex(filter_string, 1);
1528
1529 if(!r->isValid()) {
1530 delete r;
1531 conffile.entryException(entry, "invalid user-filter regular expression");
1532 }
1533
1534 user_filters.push_back(r);
1535 }
1536 }
1537
1538 if((entry = gource_settings->getEntry("user-show-filter")) != 0) {
1539
1540 ConfEntryList* filters = gource_settings->getEntries("user-show-filter");
1541
1542 for(ConfEntryList::iterator it = filters->begin(); it != filters->end(); it++) {
1543
1544 entry = *it;
1545
1546 if(!entry->hasValue()) conffile.entryException(entry, "specify user-show-filter (regex)");
1547
1548 std::string filter_string = entry->getString();
1549
1550 Regex* r = new Regex(filter_string, 1);
1551
1552 if(!r->isValid()) {
1553 delete r;
1554 conffile.entryException(entry, "invalid user-show-filter regular expression");
1555 }
1556
1557 user_show_filters.push_back(r);
1558 }
1559 }
1560
1561 if((entry = gource_settings->getEntry("dir-name-depth")) != 0) {
1562
1563 if(!entry->hasValue()) conffile.entryException(entry, "specify dir-name-depth (depth)");
1564
1565 dir_name_depth = entry->getInt();
1566
1567 if(dir_name_depth <= 0) {
1568 conffile.invalidValueException(entry);
1569 }
1570 }
1571
1572 if((entry = gource_settings->getEntry("dir-name-position")) != 0) {
1573
1574 if(!entry->hasValue()) conffile.entryException(entry, "specify dir-name-position (float)");
1575
1576 dir_name_position = entry->getFloat();
1577
1578 if(dir_name_position < 0.1f || dir_name_position > 1.0f) {
1579 conffile.entryException(entry, "dir-name-position outside of range 0.1 - 1.0 (inclusive)");
1580 }
1581 }
1582
1583 //validate path
1584 if(gource_settings->hasValue("path")) {
1585 path = gource_settings->getString("path");
1586 default_path = false;
1587 }
1588
1589 if(path == "-") {
1590
1591 if(log_format.size() == 0) {
1592 throw ConfFileException("log-format required when reading from STDIN", "", 0);
1593 }
1594
1595 #ifdef _WIN32
1596 DWORD available_bytes;
1597 HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1598
1599 while(PeekNamedPipe(stdin_handle, 0, 0, 0,
1600 &available_bytes, 0) && available_bytes==0 && !std::cin.fail()) {
1601 SDL_Delay(100);
1602 }
1603 #else
1604 while(std::cin.peek() == EOF && !std::cin.fail()) SDL_Delay(100);
1605 #endif
1606
1607 std::cin.clear();
1608
1609 } else if(!path.empty() && path != ".") {
1610
1611 //remove trailing slash
1612 if(path[path.size()-1] == '\\' || path[path.size()-1] == '/') {
1613 path.resize(path.size()-1);
1614 }
1615
1616 // check path exists
1617 if(!boost::filesystem::exists(path)) {
1618 throw ConfFileException(str(boost::format("'%s' does not appear to be a valid file or directory") % path), "", 0);
1619 }
1620 }
1621 }
1622