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"
39 #include "connection.h"
41 #include "fc_cmdhelp.h"
42 #include "fc_types.h" /* LINE_BREAK */
44 #include "government.h"
45 #include "improvement.h"
51 #include "client_main.h"
54 #include "helpdlg_g.h"
57 #include "citytools.h"
59 #include "connecthand.h"
69 #include "stdinhand.h"
81 /* This formats the manual for an HTML wiki. */
83 #define HEADER "<html><head><link rel=\"stylesheet\" type=\"text/css\" "\
84 "href=\"manual.css\"/><meta http-equiv=\"Content-Type\" "\
85 "content=\"text/html; charset=UTF-8\"/></head><body>\n\n"
86 #define SECTION_BEGIN "<h3>"
87 #define SECTION_END "</h3>"
88 #define IMAGE_BEGIN "<img src=\""
89 #define IMAGE_END ".png\">"
91 #define TAIL "</body></html>"
94 #define SECTION_BEGIN "==="
95 #define SECTION_END "==="
96 #define IMAGE_BEGIN "[[Image:"
97 #define IMAGE_END ".png]]"
98 #define SEPARATOR "----\n\n"
102 /* Needed for "About Freeciv" help */
103 const char *client_string
= "freeciv-manual";
105 static char *ruleset
= NULL
;
107 /**************************************************************************
108 Replace html special characters ('&', '<' and '>').
109 **************************************************************************/
110 static char *html_special_chars(char *str
, size_t *len
)
114 buf
= fc_strrep_resize(str
, len
, "&", "&");
115 buf
= fc_strrep_resize(buf
, len
, "<", "<");
116 buf
= fc_strrep_resize(buf
, len
, ">", ">");
121 /**************************************************************************
122 Useless stubs for compiling client code.
123 **************************************************************************/
124 void popup_help_dialog_string(const char *item
)
129 void popdown_help_dialog(void)
134 enum client_states
client_state(void)
139 bool client_nation_is_in_current_set(const struct nation_type
*pnation
)
141 /* Currently, there is no way to select a nation set for freeciv-manual.
142 * Then, let's assume we want to print help for all nations. */
146 /**************************************************************************
147 Write a server manual in html format, then quit.
148 **************************************************************************/
149 static bool manual_command(void)
153 enum manuals manuals
;
154 struct connection my_conn
;
156 /* Default client access. */
157 connection_common_init(&my_conn
);
158 my_conn
.access_level
= ALLOW_CTRL
;
160 /* Reset aifill to zero */
161 game
.info
.aifill
= 0;
163 if (!load_rulesets(NULL
, FALSE
)) {
164 /* Failed to load correct ruleset */
168 for (manuals
= 0; manuals
< MANUAL_COUNT
; manuals
++) {
172 fc_snprintf(filename
, sizeof(filename
), "manual%d.html", manuals
+ 1);
174 if (!is_reg_file_for_access(filename
, TRUE
)
175 || !(doc
= fc_fopen(filename
, "w"))) {
176 log_error(_("Could not write manual file %s."), filename
);
180 fprintf(doc
, HEADER
);
181 fprintf(doc
, "<!-- Generated by freeciv-manual version %s -->\n\n",
182 freeciv_datafile_version());
185 case MANUAL_SETTINGS
:
186 fprintf(doc
, _("<h1>Freeciv %s server options</h1>\n\n"), VERSION_STRING
);
187 settings_iterate(SSET_ALL
, pset
) {
190 fprintf(doc
, SEPARATOR
);
191 fprintf(doc
, "%s%s - %s%s\n\n", SECTION_BEGIN
, setting_name(pset
),
192 _(setting_short_help(pset
)), SECTION_END
);
193 if (strlen(setting_extra_help(pset
)) > 0) {
194 char *help
= fc_strdup(_(setting_extra_help(pset
)));
195 size_t help_len
= strlen(help
) + 1;
197 fc_break_lines(help
, LINE_BREAK
);
198 help
= html_special_chars(help
, &help_len
);
199 fprintf(doc
, "<pre>%s</pre>\n\n", help
);
202 fprintf(doc
, "<p class=\"misc\">");
203 fprintf(doc
, _("Level: %s.<br>"),
204 _(sset_level_name(setting_level(pset
))));
205 fprintf(doc
, _("Category: %s.<br>"),
206 _(sset_category_name(setting_category(pset
))));
208 /* first check if the setting is locked because this is included in
209 * the function setting_is_changeable() */
210 if (setting_locked(pset
)) {
211 fprintf(doc
, _("Is locked by the ruleset."));
212 } else if (!setting_is_changeable(pset
, &my_conn
, NULL
, 0)) {
213 fprintf(doc
, _("Can only be used in server console."));
216 fprintf(doc
, "</p>\n\n");
217 setting_default_name(pset
, TRUE
, buf
, sizeof(buf
));
218 switch (setting_type(pset
)) {
220 fprintf(doc
, "<p class=\"bounds\">%s %d, %s %s, %s %d</p>\n\n",
221 _("Minimum:"), setting_int_min(pset
),
223 _("Maximum:"), setting_int_max(pset
));
229 fprintf(doc
, "<p class=\"bounds\">%s</p>\n",
230 _("Possible values:"));
231 for (i
= 0; (value
= setting_enum_val(pset
, i
, FALSE
)); i
++) {
232 fprintf(doc
, "<p class=\"bounds\"><li/> %s: \"%s\"</p>\n",
233 value
, setting_enum_val(pset
, i
, TRUE
));
241 fprintf(doc
, "<p class=\"bounds\">%s</p>\n",
242 _("Possible values (option can take any number of these):"));
243 for (i
= 0; (value
= setting_bitwise_bit(pset
, i
, FALSE
)); i
++) {
244 fprintf(doc
, "<p class=\"bounds\"><li/> %s: \"%s\"</p>\n",
245 value
, setting_bitwise_bit(pset
, i
, TRUE
));
253 if (SSET_INT
!= setting_type(pset
)) {
254 fprintf(doc
, "<p class=\"bounds\">%s %s</p>\n\n",
257 if (setting_changed(pset
)) {
258 fprintf(doc
, _("<p class=\"changed\">Value set to %s</p>\n\n"),
259 setting_value_name(pset
, TRUE
, buf
, sizeof(buf
)));
261 } settings_iterate_end
;
264 case MANUAL_COMMANDS
:
265 fprintf(doc
, _("<h1>Freeciv %s server commands</h1>\n\n"),
267 for (i
= 0; i
< CMD_NUM
; i
++) {
268 const struct command
*cmd
= command_by_number(i
);
270 fprintf(doc
, SEPARATOR
);
271 fprintf(doc
, "%s%s - %s%s\n\n", SECTION_BEGIN
, command_name(cmd
),
272 command_short_help(cmd
), SECTION_END
);
273 if (command_synopsis(cmd
)) {
274 char *cmdstr
= fc_strdup(command_synopsis(cmd
));
275 size_t cmdstr_len
= strlen(cmdstr
) + 1;
277 cmdstr
= html_special_chars(cmdstr
, &cmdstr_len
);
278 fprintf(doc
, _("<table>\n<tr>\n<td valign=\"top\">"
279 "<pre>Synopsis:</pre></td>\n<td>"));
280 fprintf(doc
, "<pre>%s</pre></td></tr></table>", cmdstr
);
283 fprintf(doc
, _("<p class=\"level\">Level: %s</p>\n\n"),
284 cmdlevel_name(command_level(cmd
)));
286 char *help
= command_extra_help(cmd
);
288 size_t help_len
= strlen(help
) + 1;
290 fc_break_lines(help
, LINE_BREAK
);
291 help
= html_special_chars(help
, &help_len
);
292 fprintf(doc
, _("<p>Description:</p>\n\n"));
293 fprintf(doc
, "<pre>%s</pre>\n\n", help
);
301 fprintf(doc
, _("<h1>Freeciv %s terrain help</h1>\n\n"),
303 fprintf(doc
, "<table><tr bgcolor=#9bc3d1><th colspan=2>%s</th>", _("Terrain"));
304 fprintf(doc
, "<th>F/P/T</th><th>%s</th>", _("Resources"));
305 fprintf(doc
, "<th>%s<br/>%s</th>", _("Move cost"), _("Defense bonus"));
306 fprintf(doc
, "<th>%s<br/>%s<br/>%s<br/>%s<br/>(%s)</th>",
307 _("Irrigation"), _("Mining"), _("Transform"),
308 /* xgettext:no-c-format */
309 _("% of Road bonus"), _("turns"));
310 fprintf(doc
, "<th>%s<br/>%s</th>",
311 _("Clean pollution"), _("Clean fallout"));
313 if (game
.control
.num_road_types
> 0) {
314 fprintf(doc
, "<th>");
316 road_type_iterate(proad
) {
317 if (++ri
< game
.control
.num_road_types
) {
318 fprintf(doc
, "%s<br/>", road_name_translation(proad
));
321 fprintf(doc
, "%s</th>", road_name_translation(proad
));
323 } road_type_iterate_end
;
324 fprintf(doc
, "</tr>\n\n");
325 terrain_type_iterate(pterrain
) {
328 if (0 == strlen(terrain_rule_name(pterrain
))) {
329 /* Must be a disabled piece of terrain */
333 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>",
334 pterrain
->graphic_str
, terrain_name_translation(pterrain
));
335 fprintf(doc
, "<td>%d/%d/%d</td>\n",
336 pterrain
->output
[O_FOOD
], pterrain
->output
[O_SHIELD
],
337 pterrain
->output
[O_TRADE
]);
339 fprintf(doc
, "<td><table width=\"100%%\">\n");
340 for (r
= pterrain
->resources
; *r
; r
++) {
341 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>"
342 "<td align=\"right\">%d/%d/%d</td></tr>\n",
344 resource_name_translation(*r
),
345 (*r
)->output
[O_FOOD
],
346 (*r
)->output
[O_SHIELD
],
347 (*r
)->output
[O_TRADE
]);
349 fprintf(doc
, "</table></td>\n");
351 fprintf(doc
, "<td align=\"center\">%d<br/>+%d%%</td>\n",
352 pterrain
->movement_cost
, pterrain
->defense_bonus
);
354 fprintf(doc
, "<td><table width=\"100%%\">\n");
355 if (pterrain
->irrigation_result
== pterrain
) {
356 fprintf(doc
, "<tr><td>+%d F</td><td align=\"right\">(%d)</td></tr>\n",
357 pterrain
->irrigation_food_incr
, pterrain
->irrigation_time
);
358 } else if (pterrain
->irrigation_result
== T_NONE
) {
359 fprintf(doc
, "<tr><td>%s</td></tr>\n", _("impossible"));
361 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
362 terrain_name_translation(pterrain
->irrigation_result
),
363 pterrain
->irrigation_time
);
365 if (pterrain
->mining_result
== pterrain
) {
366 fprintf(doc
, "<tr><td>+%d P</td><td align=\"right\">(%d)</td></tr>\n",
367 pterrain
->mining_shield_incr
, pterrain
->mining_time
);
368 } else if (pterrain
->mining_result
== T_NONE
) {
369 fprintf(doc
, "<tr><td>%s</td></tr>\n", _("impossible"));
371 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
372 terrain_name_translation(pterrain
->mining_result
),
373 pterrain
->mining_time
);
376 if (pterrain
->transform_result
) {
377 fprintf(doc
, "<tr><td>%s</td><td align=\"right\">(%d)</td></tr>\n",
378 terrain_name_translation(pterrain
->transform_result
),
379 pterrain
->transform_time
);
381 fprintf(doc
, "<tr><td>-</td><td align=\"right\">(-)</td></tr>\n");
383 fprintf(doc
, "<tr><td>%d / %d / %d</td></tr>\n</table></td>\n",
384 pterrain
->road_output_incr_pct
[O_FOOD
],
385 pterrain
->road_output_incr_pct
[O_SHIELD
],
386 pterrain
->road_output_incr_pct
[O_TRADE
]);
388 fprintf(doc
, "<td align=\"center\">%d / %d</td>",
389 pterrain
->clean_pollution_time
, pterrain
->clean_fallout_time
);
392 if (game
.control
.num_road_types
> 0) {
393 fprintf(doc
, "<td>");
395 road_type_iterate(proad
) {
396 if (++ri
< game
.control
.num_road_types
) {
397 fprintf(doc
, "%d / ", terrain_road_time(pterrain
,
398 road_number(proad
)));
400 fprintf(doc
, "%d</td>", terrain_road_time(pterrain
,
401 road_number(proad
)));
403 } road_type_iterate_end
;
404 fprintf(doc
, "</tr>\n\n");
405 } terrain_type_iterate_end
;
407 fprintf(doc
, "</table>\n");
411 case MANUAL_BUILDINGS
:
413 if (manuals
== MANUAL_BUILDINGS
) {
414 fprintf(doc
, _("<h1>Freeciv %s buildings help</h1>\n\n"), VERSION_STRING
);
416 fprintf(doc
, _("<h1>Freeciv %s wonders help</h1>\n\n"), VERSION_STRING
);
419 fprintf(doc
, "<table>\n<tr bgcolor=#9bc3d1><th colspan=2>%s</th>"
420 "<th>%s<br/>%s</th><th>%s<br/>%s</th><th>%s</th></tr>\n\n",
421 _("Name"), _("Cost"), _("Upkeep"),
422 _("Requirement"), _("Obsolete by"), _("More info"));
424 improvement_iterate(pimprove
) {
427 if (!valid_improvement(pimprove
)
428 || is_great_wonder(pimprove
) == (manuals
== MANUAL_BUILDINGS
)) {
432 helptext_building(buf
, sizeof(buf
), NULL
, NULL
, pimprove
);
434 fprintf(doc
, "<tr><td>" IMAGE_BEGIN
"%s" IMAGE_END
"</td><td>%s</td>\n"
435 "<td align=\"center\"><b>%d</b><br/>%d</td>\n<td>",
436 pimprove
->graphic_str
,
437 improvement_name_translation(pimprove
),
438 pimprove
->build_cost
,
441 requirement_vector_iterate(&pimprove
->reqs
, req
) {
442 char text
[512], text2
[512];
443 fc_snprintf(text2
, sizeof(text2
),
444 /* TRANS: improvement requires a feature to be absent. */
445 req
->negated
? _("no %s") : "%s",
446 VUT_NONE
!= req
->source
.kind
447 ? universal_name_translation(&req
->source
,
450 fprintf(doc
, "%s<br/>", text2
);
451 } requirement_vector_iterate_end
;
453 fprintf(doc
, "<em>%s</em></td>\n",
454 valid_advance(pimprove
->obsolete_by
)
455 ? advance_name_translation(pimprove
->obsolete_by
)
457 fprintf(doc
, "<td>%s</td>\n</tr>\n\n", buf
);
458 } improvement_iterate_end
;
462 /* FIXME: this doesn't resemble the wiki manual at all. */
463 fprintf(doc
, _("<h1>Freeciv %s governments help</h1>\n\n"), VERSION_STRING
);
464 governments_iterate(pgov
) {
466 fprintf(doc
, "%s%s%s\n\n", SECTION_BEGIN
,
467 government_name_translation(pgov
), SECTION_END
);
468 helptext_government(buf
, sizeof(buf
), NULL
, NULL
, pgov
);
469 fprintf(doc
, "%s\n\n", buf
);
470 } governments_iterate_end
;
480 log_normal(_("Manual file %s successfully written."), filename
);
486 /**************************************************************************
487 Entry point of whole freeciv-manual program
488 **************************************************************************/
489 int main(int argc
, char **argv
)
492 bool showhelp
= FALSE
;
493 bool showvers
= FALSE
;
495 int retval
= EXIT_SUCCESS
;
498 registry_module_init();
499 init_character_encodings(FC_DEFAULT_DATA_ENCODING
, FALSE
);
501 /* Set the default log level. */
502 srvarg
.loglevel
= LOG_NORMAL
;
504 /* parse command-line arguments... */
507 if ((option
= get_option_malloc("--ruleset", argv
, &inx
, argc
))) {
508 if (ruleset
!= NULL
) {
509 log_error(_("Multiple rulesets requested. Only one ruleset at time supported"));
514 } else if (is_option("--help", argv
[inx
])) {
517 } else if (is_option("--version", argv
[inx
])) {
519 } else if ((option
= get_option_malloc("--log", argv
, &inx
, argc
))) {
520 srvarg
.log_filename
= option
; /* Never freed. */
522 } else if (is_option("--Fatal", argv
[inx
])) {
523 if (inx
+ 1 >= argc
|| '-' == argv
[inx
+ 1][0]) {
524 srvarg
.fatal_assertions
= SIGABRT
;
525 } else if (str_to_int(argv
[inx
+ 1], &srvarg
.fatal_assertions
)) {
528 fc_fprintf(stderr
, _("Invalid signal number \"%s\".\n"),
534 } else if ((option
= get_option_malloc("--debug", argv
, &inx
, argc
))) {
535 if (!log_parse_level_str(option
, &srvarg
.loglevel
)) {
541 fc_fprintf(stderr
, _("Unrecognized option: \"%s\"\n"), argv
[inx
]);
547 /* must be before con_log_init() */
549 con_log_init(srvarg
.log_filename
, srvarg
.loglevel
,
550 srvarg
.fatal_assertions
);
551 /* logging available after this point */
553 /* Imitate a server - this is needed for as some function only work if this
557 /* Initialize game with default values */
560 /* Set ruleset user requested in to use */
561 if (ruleset
!= NULL
) {
562 sz_strlcpy(game
.server
.rulesetdir
, ruleset
);
565 settings_init(FALSE
);
567 if (showvers
&& !showhelp
) {
568 fc_fprintf(stderr
, "%s \n", freeciv_name_version());
570 } else if (showhelp
) {
571 struct cmdhelp
*help
= cmdhelp_new(argv
[0]);
574 cmdhelp_add(help
, "d",
575 /* TRANS: "debug" is exactly what user must type, do not translate. */
577 _("Set debug log level (%d to %d, or %d:file1,min,max:...)"),
578 LOG_FATAL
, LOG_DEBUG
, LOG_DEBUG
);
580 cmdhelp_add(help
, "d",
581 /* TRANS: "debug" is exactly what user must type, do not translate. */
583 _("Set debug log level (%d to %d)"),
584 LOG_FATAL
, LOG_VERBOSE
);
587 cmdhelp_add(help
, "F",
588 /* TRANS: "Fatal" is exactly what user must type, do not translate. */
590 _("Raise a signal on failed assertion"));
592 cmdhelp_add(help
, "h", "help",
593 _("Print a summary of the options"));
594 cmdhelp_add(help
, "l",
595 /* TRANS: "log" is exactly what user must type, do not translate. */
597 _("Use FILE as logfile"));
598 cmdhelp_add(help
, "r",
599 /* TRANS: "ruleset" is exactly what user must type, do not translate. */
600 _("ruleset RULESET"),
601 _("Make manual for RULESET"));
602 cmdhelp_add(help
, "v", "version",
603 _("Print the version number"));
605 /* The function below prints a header and footer for the options.
606 * Furthermore, the options are sorted. */
607 cmdhelp_display(help
, TRUE
, FALSE
, TRUE
);
608 cmdhelp_destroy(help
);
613 if (!manual_command()) {
614 retval
= EXIT_FAILURE
;
620 registry_module_close();