Instance.init()
[nikiroo-utils.git] / src / be / nikiroo / fanfix / Main.java
1 package be.nikiroo.fanfix;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import javax.net.ssl.SSLException;
11
12 import be.nikiroo.fanfix.bundles.Config;
13 import be.nikiroo.fanfix.bundles.StringId;
14 import be.nikiroo.fanfix.data.Chapter;
15 import be.nikiroo.fanfix.data.Story;
16 import be.nikiroo.fanfix.library.BasicLibrary;
17 import be.nikiroo.fanfix.library.CacheLibrary;
18 import be.nikiroo.fanfix.library.LocalLibrary;
19 import be.nikiroo.fanfix.library.RemoteLibrary;
20 import be.nikiroo.fanfix.library.RemoteLibraryServer;
21 import be.nikiroo.fanfix.output.BasicOutput;
22 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
23 import be.nikiroo.fanfix.reader.BasicReader;
24 import be.nikiroo.fanfix.reader.Reader;
25 import be.nikiroo.fanfix.reader.Reader.ReaderType;
26 import be.nikiroo.fanfix.searchable.BasicSearchable;
27 import be.nikiroo.fanfix.supported.BasicSupport;
28 import be.nikiroo.fanfix.supported.SupportType;
29 import be.nikiroo.utils.Progress;
30 import be.nikiroo.utils.Version;
31 import be.nikiroo.utils.serial.server.ServerObject;
32
33 /**
34 * Main program entry point.
35 *
36 * @author niki
37 */
38 public class Main {
39 private enum MainAction {
40 IMPORT, EXPORT, CONVERT, READ, READ_URL, LIST, HELP, SET_READER, START, VERSION, SERVER, STOP_SERVER, REMOTE, SET_SOURCE, SET_TITLE, SET_AUTHOR, SEARCH, SEARCH_TAG
41 }
42
43 /**
44 * Main program entry point.
45 * <p>
46 * Known environment variables:
47 * <ul>
48 * <li>NOUTF: if set to 1 or 'true', the program will prefer non-unicode
49 * {@link String}s when possible</li>
50 * <li>CONFIG_DIR: a path where to look for the <tt>.properties</tt> files
51 * before taking the usual ones; they will also be saved/updated into this
52 * path when the program starts</li>
53 * <li>DEBUG: if set to 1 or 'true', the program will override the DEBUG_ERR
54 * configuration value with 'true'</li>
55 * </ul>
56 * <p>
57 * <ul>
58 * <li>--import [URL]: import into library</li>
59 * <li>--export [id] [output_type] [target]: export story to target</li>
60 * <li>--convert [URL] [output_type] [target] (+info): convert URL into
61 * target</li>
62 * <li>--read [id] ([chapter number]): read the given story from the library
63 * </li>
64 * <li>--read-url [URL] ([chapter number]): convert on the fly and read the
65 * story, without saving it</li>
66 * <li>--search: list the supported websites (where)</li>
67 * <li>--search [where] [keywords] (page [page]) (item [item]): search on
68 * the supported website and display the given results page of stories it
69 * found, or the story details if asked</li>
70 * <li>--search-tag [where]: list all the tags supported by this website</li>
71 * <li>--search-tag [index 1]... (page [page]) (item [item]): search for the
72 * given stories or subtags, tag by tag, and display information about a
73 * specific page of results or about a specific item if requested</li>
74 * <li>--list ([type]): list the stories present in the library</li>
75 * <li>--set-source [id] [new source]: change the source of the given story</li>
76 * <li>--set-title [id] [new title]: change the title of the given story</li>
77 * <li>--set-author [id] [new author]: change the author of the given story</li>
78 * <li>--set-reader [reader type]: set the reader type to CLI, TUI or LOCAL
79 * for this command</li>
80 * <li>--version: get the version of the program</li>
81 * <li>--server: start the server mode (see config file for parameters)</li>
82 * <li>--stop-server: stop the running server on this port if any</li>
83 * <li>--remote [key] [host] [port]: use a the given remote library</li>
84 * </ul>
85 *
86 * @param args
87 * see method description
88 */
89 public static void main(String[] args) {
90 // Only one line, but very important:
91 Instance.init();
92
93 String urlString = null;
94 String luid = null;
95 String sourceString = null;
96 String titleString = null;
97 String authorString = null;
98 String chapString = null;
99 String target = null;
100 String key = null;
101 MainAction action = MainAction.START;
102 Boolean plusInfo = null;
103 String host = null;
104 Integer port = null;
105 SupportType searchOn = null;
106 String search = null;
107 List<Integer> tags = new ArrayList<Integer>();
108 Integer page = null;
109 Integer item = null;
110
111 boolean noMoreActions = false;
112
113 int exitCode = 0;
114 for (int i = 0; exitCode == 0 && i < args.length; i++) {
115 // Action (--) handling:
116 if (!noMoreActions && args[i].startsWith("--")) {
117 if (args[i].equals("--")) {
118 noMoreActions = true;
119 } else {
120 try {
121 action = MainAction.valueOf(args[i].substring(2)
122 .toUpperCase().replace("-", "_"));
123 } catch (Exception e) {
124 Instance.getTraceHandler().error(
125 new IllegalArgumentException("Unknown action: "
126 + args[i], e));
127 exitCode = 255;
128 }
129 }
130
131 continue;
132 }
133
134 switch (action) {
135 case IMPORT:
136 if (urlString == null) {
137 urlString = args[i];
138 } else {
139 exitCode = 255;
140 }
141 break;
142 case EXPORT:
143 if (luid == null) {
144 luid = args[i];
145 } else if (sourceString == null) {
146 sourceString = args[i];
147 } else if (target == null) {
148 target = args[i];
149 } else {
150 exitCode = 255;
151 }
152 break;
153 case CONVERT:
154 if (urlString == null) {
155 urlString = args[i];
156 } else if (sourceString == null) {
157 sourceString = args[i];
158 } else if (target == null) {
159 target = args[i];
160 } else if (plusInfo == null) {
161 if ("+info".equals(args[i])) {
162 plusInfo = true;
163 } else {
164 exitCode = 255;
165 }
166 } else {
167 exitCode = 255;
168 }
169 break;
170 case LIST:
171 if (sourceString == null) {
172 sourceString = args[i];
173 } else {
174 exitCode = 255;
175 }
176 break;
177 case SET_SOURCE:
178 if (luid == null) {
179 luid = args[i];
180 } else if (sourceString == null) {
181 sourceString = args[i];
182 } else {
183 exitCode = 255;
184 }
185 break;
186 case SET_TITLE:
187 if (luid == null) {
188 luid = args[i];
189 } else if (sourceString == null) {
190 titleString = args[i];
191 } else {
192 exitCode = 255;
193 }
194 break;
195 case SET_AUTHOR:
196 if (luid == null) {
197 luid = args[i];
198 } else if (sourceString == null) {
199 authorString = args[i];
200 } else {
201 exitCode = 255;
202 }
203 break;
204 case READ:
205 if (luid == null) {
206 luid = args[i];
207 } else if (chapString == null) {
208 chapString = args[i];
209 } else {
210 exitCode = 255;
211 }
212 break;
213 case READ_URL:
214 if (urlString == null) {
215 urlString = args[i];
216 } else if (chapString == null) {
217 chapString = args[i];
218 } else {
219 exitCode = 255;
220 }
221 break;
222 case SEARCH:
223 if (searchOn == null) {
224 searchOn = SupportType.valueOfAllOkUC(args[i]);
225
226 if (searchOn == null) {
227 Instance.getTraceHandler().error(
228 "Website not known: <" + args[i] + ">");
229 exitCode = 41;
230 break;
231 }
232
233 if (BasicSearchable.getSearchable(searchOn) == null) {
234 Instance.getTraceHandler().error(
235 "Website not supported: " + searchOn);
236 exitCode = 42;
237 break;
238 }
239 } else if (search == null) {
240 search = args[i];
241 } else if (page != null && page == -1) {
242 try {
243 page = Integer.parseInt(args[i]);
244 } catch (Exception e) {
245 page = -2;
246 }
247 } else if (item != null && item == -1) {
248 try {
249 item = Integer.parseInt(args[i]);
250 } catch (Exception e) {
251 item = -2;
252 }
253 } else if (page == null || item == null) {
254 if (page == null && "page".equals(args[i])) {
255 page = -1;
256 } else if (item == null && "item".equals(args[i])) {
257 item = -1;
258 } else {
259 exitCode = 255;
260 }
261 } else {
262 exitCode = 255;
263 }
264 break;
265 case SEARCH_TAG:
266 if (searchOn == null) {
267 searchOn = SupportType.valueOfAllOkUC(args[i]);
268
269 if (searchOn == null) {
270 Instance.getTraceHandler().error(
271 "Website not known: <" + args[i] + ">");
272 exitCode = 255;
273 }
274
275 if (BasicSearchable.getSearchable(searchOn) == null) {
276 Instance.getTraceHandler().error(
277 "Website not supported: " + searchOn);
278 exitCode = 255;
279 }
280 } else if (page == null && item == null) {
281 if ("page".equals(args[i])) {
282 page = -1;
283 } else if ("item".equals(args[i])) {
284 item = -1;
285 } else {
286 try {
287 int index = Integer.parseInt(args[i]);
288 tags.add(index);
289 } catch (NumberFormatException e) {
290 Instance.getTraceHandler().error(
291 "Invalid tag index: " + args[i]);
292 exitCode = 255;
293 }
294 }
295 } else if (page != null && page == -1) {
296 try {
297 page = Integer.parseInt(args[i]);
298 } catch (Exception e) {
299 page = -2;
300 }
301 } else if (item != null && item == -1) {
302 try {
303 item = Integer.parseInt(args[i]);
304 } catch (Exception e) {
305 item = -2;
306 }
307 } else if (page == null || item == null) {
308 if (page == null && "page".equals(args[i])) {
309 page = -1;
310 } else if (item == null && "item".equals(args[i])) {
311 item = -1;
312 } else {
313 exitCode = 255;
314 }
315 } else {
316 exitCode = 255;
317 }
318 break;
319 case HELP:
320 exitCode = 255;
321 break;
322 case SET_READER:
323 exitCode = setReaderType(args[i]);
324 action = MainAction.START;
325 break;
326 case START:
327 exitCode = 255; // not supposed to be selected by user
328 break;
329 case VERSION:
330 exitCode = 255; // no arguments for this option
331 break;
332 case SERVER:
333 exitCode = 255; // no arguments for this option
334 break;
335 case STOP_SERVER:
336 exitCode = 255; // no arguments for this option
337 break;
338 case REMOTE:
339 if (key == null) {
340 key = args[i];
341 } else if (host == null) {
342 host = args[i];
343 } else if (port == null) {
344 port = Integer.parseInt(args[i]);
345
346 BasicLibrary lib = new RemoteLibrary(key, host, port);
347 lib = new CacheLibrary(Instance.getRemoteDir(host), lib);
348
349 BasicReader.setDefaultLibrary(lib);
350
351 action = MainAction.START;
352 } else {
353 exitCode = 255;
354 }
355 break;
356 }
357 }
358
359 final Progress mainProgress = new Progress(0, 80);
360 mainProgress.addProgressListener(new Progress.ProgressListener() {
361 private int current = mainProgress.getMin();
362
363 @Override
364 public void progress(Progress progress, String name) {
365 int diff = progress.getProgress() - current;
366 current += diff;
367
368 if (diff <= 0)
369 return;
370
371 StringBuilder builder = new StringBuilder();
372 for (int i = 0; i < diff; i++) {
373 builder.append('.');
374 }
375
376 System.err.print(builder.toString());
377
378 if (progress.isDone()) {
379 System.err.println("");
380 }
381 }
382 });
383 Progress pg = new Progress();
384 mainProgress.addProgress(pg, mainProgress.getMax());
385
386 VersionCheck updates = VersionCheck.check();
387 if (updates.isNewVersionAvailable()) {
388 // Sent to syserr so not to cause problem if one tries to capture a
389 // story content in text mode
390 System.err
391 .println("A new version of the program is available at https://github.com/nikiroo/fanfix/releases");
392 System.err.println("");
393 for (Version v : updates.getNewer()) {
394 System.err.println("\tVersion " + v);
395 System.err.println("\t-------------");
396 System.err.println("");
397 for (String it : updates.getChanges().get(v)) {
398 System.err.println("\t- " + it);
399 }
400 System.err.println("");
401 }
402 }
403
404 if (exitCode == 0) {
405 switch (action) {
406 case IMPORT:
407 exitCode = imprt(urlString, pg);
408 updates.ok(); // we consider it read
409 break;
410 case EXPORT:
411 exitCode = export(luid, sourceString, target, pg);
412 updates.ok(); // we consider it read
413 break;
414 case CONVERT:
415 exitCode = convert(urlString, sourceString, target,
416 plusInfo == null ? false : plusInfo, pg);
417 updates.ok(); // we consider it read
418 break;
419 case LIST:
420 if (BasicReader.getReader() == null) {
421 Instance.getTraceHandler()
422 .error(new Exception(
423 "No reader type has been configured"));
424 exitCode = 10;
425 break;
426 }
427 exitCode = list(sourceString);
428 break;
429 case SET_SOURCE:
430 try {
431 Instance.getLibrary().changeSource(luid, sourceString, pg);
432 } catch (IOException e1) {
433 Instance.getTraceHandler().error(e1);
434 exitCode = 21;
435 }
436 break;
437 case SET_TITLE:
438 try {
439 Instance.getLibrary().changeTitle(luid, titleString, pg);
440 } catch (IOException e1) {
441 Instance.getTraceHandler().error(e1);
442 exitCode = 22;
443 }
444 break;
445 case SET_AUTHOR:
446 try {
447 Instance.getLibrary().changeAuthor(luid, authorString, pg);
448 } catch (IOException e1) {
449 Instance.getTraceHandler().error(e1);
450 exitCode = 23;
451 }
452 break;
453 case READ:
454 if (BasicReader.getReader() == null) {
455 Instance.getTraceHandler()
456 .error(new Exception(
457 "No reader type has been configured"));
458 exitCode = 10;
459 break;
460 }
461 exitCode = read(luid, chapString, true);
462 break;
463 case READ_URL:
464 if (BasicReader.getReader() == null) {
465 Instance.getTraceHandler()
466 .error(new Exception(
467 "No reader type has been configured"));
468 exitCode = 10;
469 break;
470 }
471 exitCode = read(urlString, chapString, false);
472 break;
473 case SEARCH:
474 page = page == null ? 1 : page;
475 if (page < 0) {
476 Instance.getTraceHandler().error("Incorrect page number");
477 exitCode = 255;
478 break;
479 }
480
481 item = item == null ? 0 : item;
482 if (item < 0) {
483 Instance.getTraceHandler().error("Incorrect item number");
484 exitCode = 255;
485 break;
486 }
487
488 if (BasicReader.getReader() == null) {
489 Instance.getTraceHandler()
490 .error(new Exception(
491 "No reader type has been configured"));
492 exitCode = 10;
493 break;
494 }
495
496 try {
497 if (searchOn == null) {
498 BasicReader.getReader().search(true);
499 } else if (search != null) {
500
501 BasicReader.getReader().search(searchOn, search, page,
502 item, true);
503 } else {
504 exitCode = 255;
505 }
506 } catch (IOException e1) {
507 Instance.getTraceHandler().error(e1);
508 exitCode = 20;
509 }
510
511 break;
512 case SEARCH_TAG:
513 if (searchOn == null) {
514 exitCode = 255;
515 break;
516 }
517
518 page = page == null ? 1 : page;
519 if (page < 0) {
520 Instance.getTraceHandler().error("Incorrect page number");
521 exitCode = 255;
522 break;
523 }
524
525 item = item == null ? 0 : item;
526 if (item < 0) {
527 Instance.getTraceHandler().error("Incorrect item number");
528 exitCode = 255;
529 break;
530 }
531
532 if (BasicReader.getReader() == null) {
533 Instance.getTraceHandler()
534 .error(new Exception(
535 "No reader type has been configured"));
536 exitCode = 10;
537 break;
538 }
539
540 try {
541 BasicReader.getReader().searchTag(searchOn, page, item,
542 true, tags.toArray(new Integer[] {}));
543 } catch (IOException e1) {
544 Instance.getTraceHandler().error(e1);
545 }
546
547 break;
548 case HELP:
549 syntax(true);
550 exitCode = 0;
551 break;
552 case SET_READER:
553 exitCode = 255;
554 break;
555 case VERSION:
556 System.out
557 .println(String.format("Fanfix version %s"
558 + "%nhttps://github.com/nikiroo/fanfix/"
559 + "%n\tWritten by Nikiroo",
560 Version.getCurrentVersion()));
561 updates.ok(); // we consider it read
562 break;
563 case START:
564 if (BasicReader.getReader() == null) {
565 Instance.getTraceHandler()
566 .error(new Exception(
567 "No reader type has been configured"));
568 exitCode = 10;
569 break;
570 }
571 try {
572 BasicReader.getReader().browse(null);
573 } catch (IOException e) {
574 Instance.getTraceHandler().error(e);
575 exitCode = 66;
576 }
577 break;
578 case SERVER:
579 key = Instance.getConfig().getString(Config.SERVER_KEY);
580 port = Instance.getConfig().getInteger(Config.SERVER_PORT);
581 if (port == null) {
582 System.err.println("No port configured in the config file");
583 exitCode = 15;
584 break;
585 }
586 try {
587 ServerObject server = new RemoteLibraryServer(key, port);
588 server.setTraceHandler(Instance.getTraceHandler());
589 server.run();
590 } catch (IOException e) {
591 Instance.getTraceHandler().error(e);
592 }
593 return;
594 case STOP_SERVER:
595 key = Instance.getConfig().getString(Config.SERVER_KEY);
596 port = Instance.getConfig().getInteger(Config.SERVER_PORT);
597 if (port == null) {
598 System.err.println("No port configured in the config file");
599 exitCode = 15;
600 break;
601 }
602 try {
603 new RemoteLibrary(key, host, port).exit();
604 } catch (SSLException e) {
605 Instance.getTraceHandler().error(
606 "Bad access key for remote library");
607 exitCode = 43;
608 } catch (IOException e) {
609 Instance.getTraceHandler().error(e);
610 exitCode = 44;
611 }
612
613 break;
614 case REMOTE:
615 exitCode = 255; // should not be reachable (REMOTE -> START)
616 break;
617 }
618 }
619
620 try {
621 Instance.getTempFiles().close();
622 } catch (IOException e) {
623 Instance.getTraceHandler()
624 .error(new IOException(
625 "Cannot dispose of the temporary files", e));
626 }
627
628 if (exitCode == 255) {
629 syntax(false);
630 }
631
632 System.exit(exitCode);
633 }
634
635 /**
636 * Import the given resource into the {@link LocalLibrary}.
637 *
638 * @param urlString
639 * the resource to import
640 * @param pg
641 * the optional progress reporter
642 *
643 * @return the exit return code (0 = success)
644 */
645 public static int imprt(String urlString, Progress pg) {
646 try {
647 Story story = Instance.getLibrary().imprt(
648 BasicReader.getUrl(urlString), pg);
649 System.out.println(story.getMeta().getLuid() + ": \""
650 + story.getMeta().getTitle() + "\" imported.");
651 } catch (IOException e) {
652 Instance.getTraceHandler().error(e);
653 return 1;
654 }
655
656 return 0;
657 }
658
659 /**
660 * Export the {@link Story} from the {@link LocalLibrary} to the given
661 * target.
662 *
663 * @param luid
664 * the story LUID
665 * @param typeString
666 * the {@link OutputType} to use
667 * @param target
668 * the target
669 * @param pg
670 * the optional progress reporter
671 *
672 * @return the exit return code (0 = success)
673 */
674 public static int export(String luid, String typeString, String target,
675 Progress pg) {
676 OutputType type = OutputType.valueOfNullOkUC(typeString, null);
677 if (type == null) {
678 Instance.getTraceHandler().error(
679 new Exception(trans(StringId.OUTPUT_DESC, typeString)));
680 return 1;
681 }
682
683 try {
684 Instance.getLibrary().export(luid, type, target, pg);
685 } catch (IOException e) {
686 Instance.getTraceHandler().error(e);
687 return 4;
688 }
689
690 return 0;
691 }
692
693 /**
694 * List the stories of the given source from the {@link LocalLibrary}
695 * (unless NULL is passed, in which case all stories will be listed).
696 *
697 * @param source
698 * the source to list the known stories of, or NULL to list all
699 * stories
700 *
701 * @return the exit return code (0 = success)
702 */
703 private static int list(String source) {
704 BasicReader.setDefaultReaderType(ReaderType.CLI);
705 try {
706 BasicReader.getReader().browse(source);
707 } catch (IOException e) {
708 Instance.getTraceHandler().error(e);
709 return 66;
710 }
711
712 return 0;
713 }
714
715 /**
716 * Start the current reader for this {@link Story}.
717 *
718 * @param story
719 * the LUID of the {@link Story} in the {@link LocalLibrary}
720 * <b>or</b> the {@link Story} {@link URL}
721 * @param chapString
722 * which {@link Chapter} to read (starting at 1), or NULL to get
723 * the {@link Story} description
724 * @param library
725 * TRUE if the source is the {@link Story} LUID, FALSE if it is a
726 * {@link URL}
727 *
728 * @return the exit return code (0 = success)
729 */
730 private static int read(String story, String chapString, boolean library) {
731 try {
732 Reader reader = BasicReader.getReader();
733 if (library) {
734 reader.setMeta(story);
735 } else {
736 reader.setMeta(BasicReader.getUrl(story), null);
737 }
738
739 if (chapString != null) {
740 try {
741 reader.setChapter(Integer.parseInt(chapString));
742 reader.read(true);
743 } catch (NumberFormatException e) {
744 Instance.getTraceHandler().error(
745 new IOException("Chapter number cannot be parsed: "
746 + chapString, e));
747 return 2;
748 }
749 } else {
750 reader.read(true);
751 }
752 } catch (IOException e) {
753 Instance.getTraceHandler().error(e);
754 return 1;
755 }
756
757 return 0;
758 }
759
760 /**
761 * Convert the {@link Story} into another format.
762 *
763 * @param urlString
764 * the source {@link Story} to convert
765 * @param typeString
766 * the {@link OutputType} to convert to
767 * @param target
768 * the target file
769 * @param infoCover
770 * TRUE to also export the cover and info file, even if the given
771 * {@link OutputType} does not usually save them
772 * @param pg
773 * the optional progress reporter
774 *
775 * @return the exit return code (0 = success)
776 */
777 public static int convert(String urlString, String typeString,
778 String target, boolean infoCover, Progress pg) {
779 int exitCode = 0;
780
781 Instance.getTraceHandler().trace("Convert: " + urlString);
782 String sourceName = urlString;
783 try {
784 URL source = BasicReader.getUrl(urlString);
785 sourceName = source.toString();
786 if (source.toString().startsWith("file://")) {
787 sourceName = sourceName.substring("file://".length());
788 }
789
790 OutputType type = OutputType.valueOfAllOkUC(typeString, null);
791 if (type == null) {
792 Instance.getTraceHandler().error(
793 new IOException(trans(StringId.ERR_BAD_OUTPUT_TYPE,
794 typeString)));
795
796 exitCode = 2;
797 } else {
798 try {
799 BasicSupport support = BasicSupport.getSupport(source);
800
801 if (support != null) {
802 Instance.getTraceHandler().trace(
803 "Support found: " + support.getClass());
804 Progress pgIn = new Progress();
805 Progress pgOut = new Progress();
806 if (pg != null) {
807 pg.setMax(2);
808 pg.addProgress(pgIn, 1);
809 pg.addProgress(pgOut, 1);
810 }
811
812 Story story = support.process(pgIn);
813 try {
814 target = new File(target).getAbsolutePath();
815 BasicOutput.getOutput(type, infoCover, infoCover)
816 .process(story, target, pgOut);
817 } catch (IOException e) {
818 Instance.getTraceHandler().error(
819 new IOException(trans(StringId.ERR_SAVING,
820 target), e));
821 exitCode = 5;
822 }
823 } else {
824 Instance.getTraceHandler().error(
825 new IOException(trans(
826 StringId.ERR_NOT_SUPPORTED, source)));
827
828 exitCode = 4;
829 }
830 } catch (IOException e) {
831 Instance.getTraceHandler().error(
832 new IOException(trans(StringId.ERR_LOADING,
833 sourceName), e));
834 exitCode = 3;
835 }
836 }
837 } catch (MalformedURLException e) {
838 Instance.getTraceHandler()
839 .error(new IOException(trans(StringId.ERR_BAD_URL,
840 sourceName), e));
841 exitCode = 1;
842 }
843
844 return exitCode;
845 }
846
847 /**
848 * Simple shortcut method to call {link Instance#getTrans()#getString()}.
849 *
850 * @param id
851 * the ID to translate
852 *
853 * @return the translated result
854 */
855 private static String trans(StringId id, Object... params) {
856 return Instance.getTrans().getString(id, params);
857 }
858
859 /**
860 * Display the correct syntax of the program to the user to stdout, or an
861 * error message if the syntax used was wrong on stderr.
862 *
863 * @param showHelp
864 * TRUE to show the syntax help, FALSE to show "syntax error"
865 */
866 private static void syntax(boolean showHelp) {
867 if (showHelp) {
868 StringBuilder builder = new StringBuilder();
869 for (SupportType type : SupportType.values()) {
870 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
871 type.getDesc()));
872 builder.append('\n');
873 }
874
875 String typesIn = builder.toString();
876 builder.setLength(0);
877
878 for (OutputType type : OutputType.values()) {
879 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
880 type.getDesc(true)));
881 builder.append('\n');
882 }
883
884 String typesOut = builder.toString();
885
886 System.out.println(trans(StringId.HELP_SYNTAX, typesIn, typesOut));
887 } else {
888 System.err.println(trans(StringId.ERR_SYNTAX));
889 }
890 }
891
892 /**
893 * Set the default reader type for this session only (it can be changed in
894 * the configuration file, too, but this value will override it).
895 *
896 * @param readerTypeString
897 * the type
898 */
899 private static int setReaderType(String readerTypeString) {
900 try {
901 ReaderType readerType = ReaderType.valueOf(readerTypeString
902 .toUpperCase());
903 BasicReader.setDefaultReaderType(readerType);
904 return 0;
905 } catch (IllegalArgumentException e) {
906 Instance.getTraceHandler().error(
907 new IOException("Unknown reader type: " + readerTypeString,
908 e));
909 return 1;
910 }
911 }
912 }