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