1 /***********************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
29 #include "capability.h"
30 #include "fc_cmdline.h"
39 #include "connection.h"
41 #include "fc_cmdhelp.h"
42 #include "fc_interface.h"
43 #include "fc_types.h" /* LINE_BREAK */
45 #include "government.h"
46 #include "improvement.h"
52 #include "client_main.h"
55 #include "helpdlg_g.h"
59 #include "citytools.h"
61 #include "connecthand.h"
71 #include "stdinhand.h"
83 /* This formats the manual for an HTML wiki. */
84 #ifdef MANUAL_USE_HTML
85 #define FILE_EXT "html"
86 #define HEADER "<html><head><link rel=\"stylesheet\" type=\"text/css\" "\
87 "href=\"manual.css\"/><meta http-equiv=\"Content-Type\" "\
88 "content=\"text/html; charset=UTF-8\"/></head><body>\n\n"
89 #define SECTION_BEGIN "<h3>"
90 #define SECTION_END "</h3>"
91 #define IMAGE_BEGIN "<img src=\""
92 #define IMAGE_END ".png\">"
94 #define TAIL "</body></html>"
95 #else /* MANUAL_USE_HTML */
96 #define FILE_EXT "mediawiki"
98 #define SECTION_BEGIN "==="
99 #define SECTION_END "==="
100 #define IMAGE_BEGIN "[[Image:"
101 #define IMAGE_END ".png]]"
102 #define SEPARATOR "----\n\n"
104 #endif /* MANUAL_USE_HTML */
106 void insert_client_build_info(char *outbuf
, size_t outlen
);
108 /* Needed for "About Freeciv" help */
109 const char *client_string
= "freeciv-manual";
111 static char *ruleset
= NULL
;
113 /**************************************************************************
114 Replace html special characters ('&', '<' and '>').
115 **************************************************************************/
116 static char *html_special_chars(char *str
, size_t *len
)
120 buf
= fc_strrep_resize(str
, len
, "&", "&");
121 buf
= fc_strrep_resize(buf
, len
, "<", "<");
122 buf
= fc_strrep_resize(buf
, len
, ">", ">");
128 /*******************************************
129 Useless stubs for compiling client code.
132 /**************************************************************************
134 **************************************************************************/
135 void popup_help_dialog_string(const char *item
)
140 /**************************************************************************
142 **************************************************************************/
143 void popdown_help_dialog(void)
148 struct tileset
*tileset
;
150 /**************************************************************************
152 **************************************************************************/
153 const char *tileset_name_get(struct tileset
*t
)
158 /**************************************************************************
160 **************************************************************************/
161 const char *tileset_version(struct tileset
*t
)
166 /**************************************************************************
168 **************************************************************************/
169 const char *tileset_summary(struct tileset
*t
)
174 /**************************************************************************
176 **************************************************************************/
177 const char *tileset_description(struct tileset
*t
)
182 enum client_states
client_state(void)
187 bool client_nation_is_in_current_set(const struct nation_type
*pnation
)
189 /* Currently, there is no way to select a nation set for freeciv-manual.
190 * Then, let's assume we want to print help for all nations. */
194 /**************************************************************************
195 Write a server manual in the format chosen at build time, then quit.
196 **************************************************************************/
197 static bool manual_command(void)
201 enum manuals manuals
;
202 struct connection my_conn
;
204 /* Default client access. */
205 connection_common_init(&my_conn
);
206 my_conn
.access_level
= ALLOW_CTRL
;
208 /* Reset aifill to zero */
209 game
.info
.aifill
= 0;
211 if (!load_rulesets(NULL
, FALSE
, FALSE
)) {
212 /* Failed to load correct ruleset */
216 for (manuals
= 0; manuals
< MANUAL_COUNT
; manuals
++) {
220 fc_snprintf(filename
, sizeof(filename
), "%s%d.%s",
221 game
.server
.rulesetdir
, manuals
+ 1, FILE_EXT
);
223 if (!is_reg_file_for_access(filename
, TRUE
)
224 || !(doc
= fc_fopen(filename
, "w"))) {
225 log_error(_("Could not write manual file %s."), filename
);
229 fprintf(doc
, HEADER
);
230 fprintf(doc
, "<!-- Generated by freeciv-manual version %s -->\n\n",
231 freeciv_datafile_version());
234 case MANUAL_SETTINGS
:
235 fprintf(doc
, _("<h1>Freeciv %s server options</h1>\n\n"), VERSION_STRING
);
236 settings_iterate(SSET_ALL
, pset
) {
240 fprintf(doc
, SEPARATOR
);
241 fprintf(doc
, "%s%s - %s%s\n\n", SECTION_BEGIN
, setting_name(pset
),
242 _(setting_short_help(pset
)), SECTION_END
);
243 sethelp
= _(setting_extra_help(pset
, TRUE
));
244 if (strlen(sethelp
) > 0) {
245 char *help
= fc_strdup(sethelp
);
246 size_t help_len
= strlen(help
) + 1;
248 fc_break_lines(help
, LINE_BREAK
);
249 help
= html_special_chars(help
, &help_len
);
250 fprintf(doc
, "<pre>%s</pre>\n\n", help
);
253 fprintf(doc
, "<p class=\"misc\">");
254 fprintf(doc
, _("Level: %s.<br>"),
255 _(sset_level_name(setting_level(pset
))));
256 fprintf(doc
, _("Category: %s.<br>"),
257 _(sset_category_name(setting_category(pset
))));
259 /* first check if the setting is locked because this is included in
260 * the function setting_is_changeable() */
261 if (setting_locked(pset
)) {
262 fprintf(doc
, _("Is locked by the ruleset."));
263 } else if (!setting_is_changeable(pset
, &my_conn
, NULL
, 0)) {
264 fprintf(doc
, _("Can only be used in server console."));
267 fprintf(doc
, "</p>\n\n");
268 setting_default_name(pset
, TRUE
, buf
, sizeof(buf
));
269 switch (setting_type(pset
)) {
271 fprintf(doc
, "<p class=\"bounds\">%s %d, %s %s, %s %d</p>\n\n",
272 _("Minimum:"), setting_int_min(pset
),
274 _("Maximum:"), setting_int_max(pset
));
280 fprintf(doc
, "<p class=\"bounds\">%s</p>\n",
281 _("Possible values:"));
282 for (i
= 0; (value
= setting_enum_val(pset
, i
, FALSE
)); i
++) {
283 fprintf(doc
, "<p class=\"bounds\"><li/> %s: \"%s\"</p>\n",
284 value
, setting_enum_val(pset
, i
, TRUE
));
292 fprintf(doc
, "<p class=\"bounds\">%s</p>\n",
293 _("Possible values (option can take any number of these):"));
294 for (i
= 0; (value
= setting_bitwise_bit(pset
, i
, FALSE
)); i
++) {
295 fprintf(doc
, "<p class=\"bounds\"><li/> %s: \"%s\"</p>\n",
296 value
, setting_bitwise_bit(pset
, i
, TRUE
));
304 if (SSET_INT
!= setting_type(pset
)) {
305 fprintf(doc
, "<p class=\"bounds\">%s %s</p>\n\n",
308 if (setting_non_default(pset
)) {
309 fprintf(doc
, _("<p class=\"changed\">Value set to %s</p>\n\n"),
310 setting_value_name(pset
, TRUE
, buf
, sizeof(buf
)));
312 } settings_iterate_end
;
315 case MANUAL_COMMANDS
:
316 fprintf(doc
, _("<h1>Freeciv %s server commands</h1>\n\n"),
318 for (i
= 0; i
< CMD_NUM
; i
++) {
319 const struct command
*cmd
= command_by_number(i
);
321 fprintf(doc
, SEPARATOR
);
322 fprintf(doc
, "%s%s - %s%s\n\n", SECTION_BEGIN
, command_name(cmd
),
323 command_short_help(cmd
), SECTION_END
);
324 if (command_synopsis(cmd
)) {
325 char *cmdstr
= fc_strdup(command_synopsis(cmd
));
326 size_t cmdstr_len
= strlen(cmdstr
) + 1;
328 cmdstr
= html_special_chars(cmdstr
, &cmdstr_len
);
329 fprintf(doc
, _("<table>\n<tr>\n<td valign=\"top\">"
330 "<pre>Synopsis:</pre></td>\n<td>"));
331 fprintf(doc
, "<pre>%s</pre></td></tr></table>", cmdstr
);
334 fprintf(doc
, _("<p class=\"level\">Level: %s</p>\n\n"),
335 cmdlevel_name(command_level(cmd
)));
337 char *help
= command_extra_help(cmd
);
339 size_t help_len
= strlen(help
) + 1;
341 fc_break_lines(help
, LINE_BREAK
);
342 help
= html_special_chars(help
, &help_len
);
343 fprintf(doc
, _("<p>Description:</p>\n\n"));
344 fprintf(doc
, "<pre>%s</pre>\n\n", help
);
352 fprintf(doc
, _("<h1>Freeciv %s terrain help</h1>\n\n"),
354 fprintf(doc
, "<table><tr bgcolor=#9bc3d1><th colspan=2>%s</th>", _("Terrain"));
355 fprintf(doc
, "<th>F/P/T</th><th>%s</th>", _("Resources"));
356 fprintf(doc
, "<th>%s<br/>%s</th>", _("Move cost"), _("Defense bonus"));
357 fprintf(doc
, "<th>%s<br/>%s<br/>%s<br/>%s<br/>(%s)</th>",
358 _("Irrigation"), _("Mining"), _("Transform"),
359 /* xgettext:no-c-format */
360 _("% of Road bonus"), _("turns"));
361 fprintf(doc
, "<th>%s<br/>%s</th>",
362 _("Clean pollution"), _("Clean fallout"));
364 if (game
.control
.num_road_types
> 0) {
365 fprintf(doc
, "<th>");
367 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
368 if (++ri
< game
.control
.num_road_types
) {
369 fprintf(doc
, "%s<br/>", extra_name_translation(pextra
));
372 fprintf(doc
, "%s</th>", extra_name_translation(pextra
));
374 } extra_type_by_cause_iterate_end
;
375 fprintf(doc
, "</tr>\n\n");
376 terrain_type_iterate(pterrain
) {
379 if (0 == strlen(terrain_rule_name(pterrain
))) {
380 /* Must be a disabled piece of terrain */
384 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>",
385 pterrain
->graphic_str
, terrain_name_translation(pterrain
));
386 fprintf(doc
, "<td>%d/%d/%d</td>\n",
387 pterrain
->output
[O_FOOD
], pterrain
->output
[O_SHIELD
],
388 pterrain
->output
[O_TRADE
]);
390 fprintf(doc
, "<td><table width=\"100%%\">\n");
391 for (r
= pterrain
->resources
; *r
; r
++) {
392 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>"
393 "<td align=\"right\">%d/%d/%d</td></tr>\n",
395 resource_name_translation(*r
),
396 (*r
)->output
[O_FOOD
],
397 (*r
)->output
[O_SHIELD
],
398 (*r
)->output
[O_TRADE
]);
400 fprintf(doc
, "</table></td>\n");
402 fprintf(doc
, "<td align=\"center\">%d<br/>+%d%%</td>\n",
403 pterrain
->movement_cost
, pterrain
->defense_bonus
);
405 fprintf(doc
, "<td><table width=\"100%%\">\n");
406 if (pterrain
->irrigation_result
== pterrain
) {
407 fprintf(doc
, "<tr><td>+%d F</td><td align=\"right\">(%d)</td></tr>\n",
408 pterrain
->irrigation_food_incr
, pterrain
->irrigation_time
);
409 } else if (pterrain
->irrigation_result
== T_NONE
) {
410 fprintf(doc
, "<tr><td>%s</td></tr>\n", _("impossible"));
412 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
413 terrain_name_translation(pterrain
->irrigation_result
),
414 pterrain
->irrigation_time
);
416 if (pterrain
->mining_result
== pterrain
) {
417 fprintf(doc
, "<tr><td>+%d P</td><td align=\"right\">(%d)</td></tr>\n",
418 pterrain
->mining_shield_incr
, pterrain
->mining_time
);
419 } else if (pterrain
->mining_result
== T_NONE
) {
420 fprintf(doc
, "<tr><td>%s</td></tr>\n", _("impossible"));
422 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
423 terrain_name_translation(pterrain
->mining_result
),
424 pterrain
->mining_time
);
427 if (pterrain
->transform_result
) {
428 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
429 terrain_name_translation(pterrain
->transform_result
),
430 pterrain
->transform_time
);
432 fprintf(doc
, "<tr><td>-</td><td align=\"right\">(-)</td></tr>\n");
434 fprintf(doc
, "<tr><td>%d / %d / %d</td></tr>\n</table></td>\n",
435 pterrain
->road_output_incr_pct
[O_FOOD
],
436 pterrain
->road_output_incr_pct
[O_SHIELD
],
437 pterrain
->road_output_incr_pct
[O_TRADE
]);
439 fprintf(doc
, "<td align=\"center\">%d / %d</td>",
440 pterrain
->clean_pollution_time
, pterrain
->clean_fallout_time
);
443 if (game
.control
.num_road_types
> 0) {
444 fprintf(doc
, "<td>");
446 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
447 if (++ri
< game
.control
.num_road_types
) {
448 fprintf(doc
, "%d / ", terrain_extra_build_time(pterrain
, ACTIVITY_GEN_ROAD
,
451 fprintf(doc
, "%d</td>", terrain_extra_build_time(pterrain
, ACTIVITY_GEN_ROAD
,
454 } extra_type_by_cause_iterate_end
;
455 fprintf(doc
, "</tr>\n\n");
456 } terrain_type_iterate_end
;
458 fprintf(doc
, "</table>\n");
462 case MANUAL_BUILDINGS
:
464 if (manuals
== MANUAL_BUILDINGS
) {
465 fprintf(doc
, _("<h1>Freeciv %s buildings help</h1>\n\n"), VERSION_STRING
);
467 fprintf(doc
, _("<h1>Freeciv %s wonders help</h1>\n\n"), VERSION_STRING
);
470 fprintf(doc
, "<table>\n<tr bgcolor=#9bc3d1><th colspan=2>%s</th>"
471 "<th>%s<br/>%s</th><th>%s<br/>%s</th><th>%s</th></tr>\n\n",
472 _("Name"), _("Cost"), _("Upkeep"),
473 _("Requirement"), _("Obsolete by"), _("More info"));
475 improvement_iterate(pimprove
) {
477 struct advance
*obs_tech
= NULL
;
479 if (!valid_improvement(pimprove
)
480 || is_great_wonder(pimprove
) == (manuals
== MANUAL_BUILDINGS
)) {
484 helptext_building(buf
, sizeof(buf
), NULL
, NULL
, pimprove
);
486 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>\n"
487 "<td align=\"center\"><b>%d</b><br/>%d</td>\n<td>",
488 pimprove
->graphic_str
,
489 improvement_name_translation(pimprove
),
490 pimprove
->build_cost
,
493 requirement_vector_iterate(&pimprove
->reqs
, req
) {
494 char text
[512], text2
[512];
495 fc_snprintf(text2
, sizeof(text2
),
496 /* TRANS: improvement requires a feature to be absent. */
497 req
->present
? "%s" : _("no %s"),
498 VUT_NONE
!= req
->source
.kind
499 ? universal_name_translation(&req
->source
,
502 fprintf(doc
, "%s<br/>", text2
);
503 } requirement_vector_iterate_end
;
505 requirement_vector_iterate(&pimprove
->obsolete_by
, pobs
) {
506 if (pobs
->source
.kind
== VUT_ADVANCE
) {
507 obs_tech
= pobs
->source
.value
.advance
;
510 } requirement_vector_iterate_end
;
512 fprintf(doc
, "<em>%s</em></td>\n",
514 ? advance_name_translation(obs_tech
)
516 fprintf(doc
, "<td>%s</td>\n</tr>\n\n", buf
);
517 } improvement_iterate_end
;
518 fprintf(doc
, "</table>");
522 /* FIXME: this doesn't resemble the wiki manual at all. */
523 fprintf(doc
, _("<h1>Freeciv %s governments help</h1>\n\n"), VERSION_STRING
);
524 governments_iterate(pgov
) {
526 fprintf(doc
, "%s%s%s\n\n", SECTION_BEGIN
,
527 government_name_translation(pgov
), SECTION_END
);
528 helptext_government(buf
, sizeof(buf
), NULL
, NULL
, pgov
);
529 fprintf(doc
, "%s\n\n", buf
);
530 } governments_iterate_end
;
540 log_normal(_("Manual file %s successfully written."), filename
);
546 /**************************************************************************
547 Entry point of whole freeciv-manual program
548 **************************************************************************/
549 int main(int argc
, char **argv
)
552 bool showhelp
= FALSE
;
553 bool showvers
= FALSE
;
555 int retval
= EXIT_SUCCESS
;
558 registry_module_init();
559 init_character_encodings(FC_DEFAULT_DATA_ENCODING
, FALSE
);
561 /* Set the default log level. */
562 srvarg
.loglevel
= LOG_NORMAL
;
564 /* parse command-line arguments... */
567 if ((option
= get_option_malloc("--ruleset", argv
, &inx
, argc
, TRUE
))) {
568 if (ruleset
!= NULL
) {
569 fc_fprintf(stderr
, _("Multiple rulesets requested. Only one "
570 "ruleset at a time is supported.\n"));
574 } else if (is_option("--help", argv
[inx
])) {
577 } else if (is_option("--version", argv
[inx
])) {
579 } else if ((option
= get_option_malloc("--log", argv
, &inx
, argc
, TRUE
))) {
580 srvarg
.log_filename
= option
;
581 #ifndef FREECIV_NDEBUG
582 } else if (is_option("--Fatal", argv
[inx
])) {
583 if (inx
+ 1 >= argc
|| '-' == argv
[inx
+ 1][0]) {
584 srvarg
.fatal_assertions
= SIGABRT
;
585 } else if (str_to_int(argv
[inx
+ 1], &srvarg
.fatal_assertions
)) {
588 fc_fprintf(stderr
, _("Invalid signal number \"%s\".\n"),
593 #endif /* FREECIV_NDEBUG */
594 } else if ((option
= get_option_malloc("--debug", argv
, &inx
, argc
, FALSE
))) {
595 if (!log_parse_level_str(option
, &srvarg
.loglevel
)) {
601 fc_fprintf(stderr
, _("Unrecognized option: \"%s\"\n"), argv
[inx
]);
607 /* must be before con_log_init() */
609 con_log_init(srvarg
.log_filename
, srvarg
.loglevel
,
610 srvarg
.fatal_assertions
);
611 /* logging available after this point */
613 /* Imitate a server - this is needed for as some function only work if this
617 /* Initialize game with default values */
620 /* Set ruleset user requested in to use */
621 if (ruleset
!= NULL
) {
622 sz_strlcpy(game
.server
.rulesetdir
, ruleset
);
625 settings_init(FALSE
);
627 if (showvers
&& !showhelp
) {
628 fc_fprintf(stderr
, "%s \n", freeciv_name_version());
630 } else if (showhelp
) {
631 struct cmdhelp
*help
= cmdhelp_new(argv
[0]);
634 cmdhelp_add(help
, "d",
635 /* TRANS: "debug" is exactly what user must type, do not translate. */
637 _("Set debug log level (%d to %d, or %d:file1,min,max:...)"),
638 LOG_FATAL
, LOG_DEBUG
, LOG_DEBUG
);
640 cmdhelp_add(help
, "d",
641 /* TRANS: "debug" is exactly what user must type, do not translate. */
643 _("Set debug log level (%d to %d)"),
644 LOG_FATAL
, LOG_VERBOSE
);
646 #ifndef FREECIV_NDEBUG
647 cmdhelp_add(help
, "F",
648 /* TRANS: "Fatal" is exactly what user must type, do not translate. */
650 _("Raise a signal on failed assertion"));
651 #endif /* FREECIV_NDEBUG */
652 cmdhelp_add(help
, "h", "help",
653 _("Print a summary of the options"));
654 cmdhelp_add(help
, "l",
655 /* TRANS: "log" is exactly what user must type, do not translate. */
657 _("Use FILE as logfile"));
658 cmdhelp_add(help
, "r",
659 /* TRANS: "ruleset" is exactly what user must type, do not translate. */
660 _("ruleset RULESET"),
661 _("Make manual for RULESET"));
662 cmdhelp_add(help
, "v", "version",
663 _("Print the version number"));
665 /* The function below prints a header and footer for the options.
666 * Furthermore, the options are sorted. */
667 cmdhelp_display(help
, TRUE
, FALSE
, TRUE
);
668 cmdhelp_destroy(help
);
673 if (!manual_command()) {
674 retval
= EXIT_FAILURE
;
678 registry_module_close();
681 cmdline_option_values_free();
686 /**************************************************************************
687 Empty function required by helpdata
688 **************************************************************************/
689 void insert_client_build_info(char *outbuf
, size_t outlen
)