1 /* Xconq documentation writer.
2 Copyright (C) 2004 Eric A. McDonald
3
4 Xconq is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version. See the file COPYING. */
8
9 /* This writes out documentation of game modules to various file formats. */
10
11 #include "conq.h"
12 #include <wait.h>
13 #include "kpublic.h"
14 #include "print.h"
15 #include "cmdline.h"
16 #include "imf.h"
17 #include "ui.h"
18
19 extern Side* dside;
20 Side *defaultside = NULL;
21
22 /* This structure maintains state that is local to a side's display.
23 At the very least, it must track when the display is open and closed. */
24
25 typedef struct a_ui {
26 int active;
27 } UI;
28
29 /* Box for storing the results of command-line parsing. */
30
31 typedef struct param_box_cli {
32 int flags;
33 HelpOutputMode houtmode;
34 char **modnamelist;
35 } CLIParamBox;
36
37 #define CLI_FLAG_DOCUMENT_GAMES 1
38 #define CLI_FLAG_DOCUMENT_COMMANDS 2
39 #define CLI_FLAG_DOCUMENT_SYMBOLS 4
40 #define CLI_FLAG_MULTIPLE_GAMES 8
41 #define CLI_FLAG_ALL_GAMES 16
42 #define CLI_FLAG_INDEX_GAMES 32
43
44 /* Tree structure to emulate game hierarchy. */
45
46 typedef struct game_tree_node {
47 Module *module;
48 struct game_tree_node *sibling;
49 struct game_tree_node *child;
50 } GameTreeNode;
51
52 /* Prototypes of Xcscribe functions. */
53
54 static void parse_xcscribe_command_line (CLIParamBox *pboxcli, int argc,
55 char *argv []);
56 static void show_xscribe_help_usage(char *argv0);
57 static void write_game_index(CLIParamBox *pboxcli);
58 static void add_to_game_tree(GameTreeNode **gametree, Module *module);
59 static GameTreeNode *create_game_tree_node(Module *module);
60 static GameTreeNode *find_game_in_tree(GameTreeNode *gametree, Module *module);
61 static void write_game_index_aux(GameTreeNode *gametree, CLIParamBox *pboxcli,
62 int indentlvl);
63 static void write_help_files(HelpOutputMode houtmode, char *docdir,
64 char *curmodulename);
65
66 #define MNAME_BUF_SIZE 255
67 #define ARGLIST_SIZE 6
68
69 /* Master-worker process model. Parent forks out a child process for each
70 game module to be documented in sequential order. */
71
72 int
main(int argc,char * argv[])73 main(int argc, char *argv[])
74 {
75 int i = 0;
76 CLIParamBox pboxcli;
77 char curmodulename [MNAME_BUF_SIZE];
78 Module *curmodule = NULL;
79 int idxcurmodule = 0;
80 pid_t pid = 0;
81 int childstatus = 0, waitresult = 0;
82 char *homedir = NULL, *docdir = NULL;
83
84 /* Prep some data structures. */
85 memset(curmodulename, 0, MNAME_BUF_SIZE);
86 /* Setup the library path. */
87 init_library_path(NULL);
88 /* Initialize Xconq. */
89 clear_game_modules();
90 #ifdef DEBUGGING
91 init_debug_to_stdout();
92 #endif /* DEBUGGING */
93 init_data_structures();
94 /* Collect complete list of games. */
95 collect_possible_games();
96 if (!possible_games)
97 init_error("No games were found in your game library!");
98 /* Parse the command line. */
99 parse_xcscribe_command_line(&pboxcli, argc, argv);
100 /* Prepare documentation directory. */
101 homedir = game_homedir();
102 docdir = (char *)xmalloc(strlen(homedir) + 20);
103 make_pathname(homedir, "doc", NULL, docdir);
104 if (access(docdir, F_OK)) {
105 mkdir(docdir, 0755);
106 /* TODO: Should handle any errors that result from this. */
107 }
108 /* Set some help output options. */
109 set_help_output_cc(HELP_OUTPUT_CC_FILES);
110 set_help_output_mode(pboxcli.houtmode);
111 set_help_output_dir(docdir);
112 /* Write master game index, if requested. */
113 if (pboxcli.flags & CLI_FLAG_INDEX_GAMES)
114 write_game_index(&pboxcli);
115 /* Fork/exec loop. */
116 while (1) {
117 /* Load the name of the module to process. */
118 if (pboxcli.flags & CLI_FLAG_MULTIPLE_GAMES) {
119 if (pboxcli.flags & CLI_FLAG_ALL_GAMES) {
120 if (idxcurmodule >= numgames)
121 break;
122 else
123 strncpy(curmodulename, (possible_games[idxcurmodule])->name,
124 MNAME_BUF_SIZE);
125 }
126 else {
127 if (pboxcli.modnamelist[idxcurmodule])
128 strncpy(curmodulename, pboxcli.modnamelist[idxcurmodule],
129 MNAME_BUF_SIZE);
130 else
131 break;
132 }
133 }
134 else {
135 if (pboxcli.flags & CLI_FLAG_DOCUMENT_GAMES) {
136 if (idxcurmodule)
137 break;
138 else
139 strncpy(curmodulename, pboxcli.modnamelist[0],
140 MNAME_BUF_SIZE);
141 }
142 }
143 /* Fork, if multiple games to process. */
144 if (pboxcli.flags & CLI_FLAG_MULTIPLE_GAMES) {
145 pid = fork();
146 /* If error... */
147 if (0 > pid) {
148 perror("xcscribe");
149 run_error("Failed to start next doc writer process");
150 exit(1);
151 }
152 }
153 /* If parent and multiple games to be written... */
154 if ((pboxcli.flags & CLI_FLAG_MULTIPLE_GAMES) && pid) {
155 /* Wait for child to complete. */
156 waitresult = waitpid(pid, &childstatus, 0);
157 if (0 > waitresult) {
158 perror("xcscribe");
159 run_error("Waiting for a doc writer process failed");
160 exit(1);
161 }
162 if (waitresult == pid) {
163 if (WEXITSTATUS(childstatus))
164 run_error("Doc writer process terminated abnormally");
165 }
166 /* Increment module index. */
167 ++idxcurmodule;
168 /* Loop again. */
169 continue;
170 } /* parent */
171 /* If child or single game to be written... */
172 else {
173 /* TODO: Conditionally write games only if CLI_FLAG_DOCUMENT_GAMES
174 is set. */
175 /* Find the specified module. */
176 for (i = 0; i < numgames; ++i) {
177 if (!strcmp(curmodulename, (possible_games[i])->name)) {
178 mainmodule = curmodule = possible_games[i];
179 break;
180 }
181 }
182 /* Make sure that we found the specified module. */
183 if (NULL == curmodule) {
184 init_error("Could not find the specified game module.");
185 exit(1);
186 }
187 /* Load the designated module and any modules that it relies
188 upon. */
189 load_all_modules();
190 /* See if we have something resembling a valid game. */
191 check_game_validity();
192 /* Write out the help files. */
193 write_help_files(pboxcli.houtmode, docdir, curmodulename);
194 /* Return */
195 return 0;
196 }
197 } /* Fork/exec loop. */
198 return 0;
199 }
200
201 /* Parse command line. */
202
203 static void
parse_xcscribe_command_line(CLIParamBox * pboxcli,int argc,char * argv[])204 parse_xcscribe_command_line (CLIParamBox *pboxcli, int argc, char *argv [])
205 {
206 int i = 0, modnamelistidx = 0;
207
208 /* Sanity checks. */
209 assert_error(pboxcli,
210 "Attempted to use a NULL command line argument container");
211 assert_error((1 <= argc), "Invalid number of command line arguments");
212 assert_error(argv, "Invalid command line arguments list");
213 /* Initialize parambox. */
214 pboxcli->flags = 0;
215 pboxcli->houtmode = HELP_OUTPUT_HTML;
216 pboxcli->modnamelist = (char **)xmalloc((numgames + 1) * sizeof(char *));
217 memset(pboxcli->modnamelist, 0, (numgames + 1) * sizeof(char *));
218 /* Parse the args, if any. */
219 if (argc > 1) {
220 for (i = 1; i < argc; ++i) {
221 if (!strncmp(argv[i], "--text", 6)
222 || !strncmp(argv[i], "-T", 2))
223 pboxcli->houtmode = HELP_OUTPUT_PLAIN_TEXT;
224 else if (!strncmp(argv[i], "--html", 6)
225 || !strncmp(argv[i], "-H", 2))
226 pboxcli->houtmode = HELP_OUTPUT_HTML;
227 else if (!strncmp(argv[i], "--all-games", 11)
228 || !strncmp(argv[i], "-AG", 3)) {
229 pboxcli->flags |= CLI_FLAG_DOCUMENT_GAMES;
230 pboxcli->flags |= CLI_FLAG_MULTIPLE_GAMES;
231 pboxcli->flags |= CLI_FLAG_ALL_GAMES;
232 }
233 else if (!strncmp(argv[i], "--game-index", 12)
234 || !strncmp(argv[i], "-IG", 3)) {
235 pboxcli->flags |= CLI_FLAG_INDEX_GAMES;
236 }
237 else if (!strncmp(argv[i], "--all-commands", 14)
238 || !strncmp(argv[i], "-AC", 3)) {
239 pboxcli->flags |= CLI_FLAG_DOCUMENT_COMMANDS;
240 printf("\n\"%s\" is not yet implemented.", argv[i]);
241 }
242 else if (!strncmp(argv[i], "--all-symbols", 13)
243 || !strncmp(argv[i], "-AS", 3)) {
244 pboxcli->flags |= CLI_FLAG_DOCUMENT_SYMBOLS;
245 printf("\n\"%s\" is not yet implemented.", argv[i]);
246 }
247 /* NOTE: Parsing of the "all" argument must go after the
248 "all-*" arguments. */
249 else if (!strncmp(argv[i], "--all", 5)
250 || !strncmp(argv[i], "-A", 2)) {
251 pboxcli->flags |= CLI_FLAG_DOCUMENT_GAMES;
252 pboxcli->flags |= CLI_FLAG_DOCUMENT_COMMANDS;
253 pboxcli->flags |= CLI_FLAG_DOCUMENT_SYMBOLS;
254 pboxcli->flags |= CLI_FLAG_MULTIPLE_GAMES;
255 pboxcli->flags |= CLI_FLAG_ALL_GAMES;
256 pboxcli->flags |= CLI_FLAG_INDEX_GAMES;
257 }
258 else if (!strncmp(argv[i], "--help", 6)
259 || !strncmp(argv[i], "-help", 5)
260 || !strncmp(argv[i], "-?", 2)
261 || !strncmp(argv[i], "/HELP", 5)
262 || !strncmp(argv[i], "/help", 5)
263 || !strncmp(argv[i], "/?", 2)) {
264 show_xscribe_help_usage(argv[0]);
265 exit(0);
266 }
267 else {
268 pboxcli->flags |= CLI_FLAG_DOCUMENT_GAMES;
269 if (modnamelistidx > 0)
270 pboxcli->flags |= CLI_FLAG_MULTIPLE_GAMES;
271 pboxcli->modnamelist[modnamelistidx++] = argv[i];
272 }
273 }
274 } /* argc > 1 */
275 /* Set reasonable defaults if nothing specified. */
276 else {
277 pboxcli->flags |= CLI_FLAG_DOCUMENT_GAMES;
278 pboxcli->flags |= CLI_FLAG_MULTIPLE_GAMES;
279 pboxcli->flags |= CLI_FLAG_ALL_GAMES;
280 pboxcli->flags |= CLI_FLAG_INDEX_GAMES;
281 } /* args == 1 */
282 /* Some final touchups. */
283 if (!(pboxcli->modnamelist[0])
284 && !(pboxcli->flags & CLI_FLAG_MULTIPLE_GAMES)) {
285 pboxcli->flags |= CLI_FLAG_MULTIPLE_GAMES;
286 pboxcli->flags |= CLI_FLAG_ALL_GAMES;
287 if (!(pboxcli->flags & CLI_FLAG_INDEX_GAMES)) {
288 pboxcli->flags |= CLI_FLAG_INDEX_GAMES;
289 pboxcli->flags |= CLI_FLAG_DOCUMENT_GAMES;
290 }
291 }
292 fflush(NULL);
293 }
294
295 /* Describe the command-line arguments. */
296
297 static void
show_xscribe_help_usage(char * argv0)298 show_xscribe_help_usage(char *argv0)
299 {
300 printf("\n\n");
301 if (!argv0)
302 printf("xcscribe");
303 else
304 printf("%s", argv0);
305 printf(" [ --all ] [ -A ] [ --all-games ] [ -AG ]");
306 printf(" [ --game-index ] [ -IG ]");
307 printf(" [ --all-commands ] [ -AC ]");
308 printf(" [ --all-symbols ] [ -AS ]");
309 printf(" [ --html ] [ -H ]");
310 printf(" [ --text ] [ -T ]");
311 printf(" [ [ <game module name> ] ... ]\n");
312 printf("\t--all | -A\t\tDocument all games, commands, and symbols.\n");
313 printf("\t--all-games | -AG\tDocument all games.\n");
314 printf("\t--game-index | -IG\tCreate a master index of all the games.\n");
315 printf("\t--all-commands | -AC\tDocument all commands.\n");
316 printf("\t--all-symbols | -AS\tDocument all symbols.\n");
317 printf("\t--html | -H\t\tProduce output in HTML.\n");
318 printf("\t--text | -T\t\tProduce output in plain text.\n");
319 printf("\n");
320 fflush(NULL);
321 }
322
323 /* Write out a file containing the index of the games. */
324
325 static void
write_game_index(CLIParamBox * pboxcli)326 write_game_index(CLIParamBox *pboxcli)
327 {
328 int i = 0, j = 0;
329 char curmodname [BUFSIZE];
330 Module *curmod = NULL;
331 GameTreeNode *gametree = NULL;
332 char idxfilename [BUFSIZE];
333 FILE *hidxfilep = NULL;
334
335 make_pathname("", "index", get_help_file_extension(), idxfilename);
336 hidxfilep = prep_help_file(idxfilename);
337 write_help_file_header(hidxfilep, "Game Index");
338 for (i = 0; i < numgames; ++i) {
339 curmod = NULL;
340 if (pboxcli->flags & CLI_FLAG_ALL_GAMES)
341 curmod = possible_games[i];
342 else {
343 memset(curmodname, 0, BUFSIZE);
344 if (!((pboxcli->modnamelist)[i]))
345 break;
346 else {
347 strncpy(curmodname, (pboxcli->modnamelist)[i], BUFSIZE);
348 for (j = 0; j < numgames; ++j) {
349 if (!strcmp(curmodname, (possible_games[j])->name)) {
350 curmod = possible_games[j];
351 break;
352 }
353 }
354 if (!curmod)
355 init_error("Could not find game module to index");
356 }
357 }
358 add_to_game_tree(&gametree, curmod);
359 }
360 set_help_toc_filep(hidxfilep);
361 write_game_index_aux(gametree, pboxcli, 0);
362 set_help_toc_filep(NULL);
363 write_help_file_footer(hidxfilep, "Game Index");
364 finish_help_file(hidxfilep);
365 }
366
367 /* Add a game module to a game tree. */
368
369 static void
add_to_game_tree(GameTreeNode ** gametree,Module * module)370 add_to_game_tree(GameTreeNode **gametree, Module *module)
371 {
372 Module *basemodule = NULL;
373 GameTreeNode *curnode = NULL;
374
375 assert_error(module, "Attempted to add a NULL game module to game tree");
376 /* Insert parent modules first. */
377 if (module->basemodulename) {
378 basemodule = get_game_module(module->basemodulename);
379 add_to_game_tree(gametree, basemodule);
380 }
381 /* If tree is empty, then create a first node for it. */
382 if (!(*gametree)) {
383 gametree[0] = create_game_tree_node(module);
384 return;
385 }
386 /* If the game is not already in the tree, then add it. */
387 if (!find_game_in_tree(gametree[0], module)) {
388 /* If parent module is in the tree, then add relative to the parent. */
389 if (module->basemodulename) {
390 curnode = find_game_in_tree(gametree[0], basemodule);
391 assert_error(curnode,
392 "Unexpected failure to find a game in game tree");
393 /* Add directly off of parent node, if first child. */
394 if (!(curnode->child)) {
395 curnode->child = create_game_tree_node(module);
396 return;
397 }
398 else
399 curnode = curnode->child;
400 }
401 /* Add independent game relative to the base of the tree. */
402 else {
403 curnode = gametree[0];
404 }
405 /* Find a free sibling slot. */
406 while (curnode->sibling)
407 curnode = curnode->sibling;
408 /* Add to free sibling slot. */
409 curnode->sibling = create_game_tree_node(module);
410 return;
411 }
412 else
413 return;
414 }
415
416 /* Create a new game tree node. */
417
418 static GameTreeNode *
create_game_tree_node(Module * module)419 create_game_tree_node(Module *module)
420 {
421 GameTreeNode *node = NULL;
422
423 assert_error(module, "Attempted to add a NULL game module to game node");
424 node = (GameTreeNode *)xmalloc(sizeof(GameTreeNode));
425 node->module = module;
426 node->child = NULL;
427 node->sibling = NULL;
428 return node;
429 }
430
431 /* Find a game in a game tree. Depth-first search. */
432
433 static GameTreeNode *
find_game_in_tree(GameTreeNode * gametree,Module * module)434 find_game_in_tree(GameTreeNode *gametree, Module *module)
435 {
436 GameTreeNode *gamebranch = NULL;
437
438 assert_error(gametree, "Attempted to search an empty game tree");
439 assert_error(module, "Attempted to find NULL game module in game tree");
440 if (!strcmp(gametree->module->name, module->name))
441 return gametree;
442 if (gametree->child) {
443 if ((gamebranch = find_game_in_tree(gametree->child, module)))
444 return gamebranch;
445 }
446 if (gametree->sibling)
447 return find_game_in_tree(gametree->sibling, module);
448 return gamebranch;
449 }
450
451 /* Write out game hierarchy into a game index file. */
452
453 static void
write_game_index_aux(GameTreeNode * gametree,CLIParamBox * pboxcli,int indentlvl)454 write_game_index_aux(GameTreeNode *gametree, CLIParamBox *pboxcli,
455 int indentlvl)
456 {
457 char gameidxname [BUFSIZE];
458
459 assert_error(gametree, "Attempted to search an empty game tree");
460 switch (pboxcli->houtmode) {
461 case HELP_OUTPUT_PLAIN_TEXT:
462 make_pathname(gametree->module->name, "index", NULL, gameidxname);
463 break;
464 case HELP_OUTPUT_HTML:
465 strncpy(gameidxname, gametree->module->name, BUFSIZE);
466 strncat(gameidxname, "/index",
467 BUFSIZE - strlen(gametree->module->name));
468 break;
469 default: break;
470 }
471 write_help_toc_entry(gameidxname, gametree->module->title, indentlvl);
472 if (gametree->child)
473 write_game_index_aux(gametree->child, pboxcli, indentlvl+1);
474 if (gametree->sibling)
475 write_game_index_aux(gametree->sibling, pboxcli, indentlvl);
476 }
477
478 /* Set up the help system to write out files in the specified format and
479 in the specified place, and then do it. */
480
481 static void
write_help_files(HelpOutputMode houtmode,char * docdir,char * curmodulename)482 write_help_files(HelpOutputMode houtmode, char *docdir, char *curmodulename)
483 {
484 char *gamedocdir = NULL;
485
486 /* Sanity checks. */
487 assert_error(docdir, "Tried to write help files to a NULL doc directory.");
488 assert_error(curmodulename, "Tried to write help for a NULL module name.");
489 assert_error(curmodulename[0],
490 "Tried to write help for an empty module name.");
491 /* Determine the game documentation directory and create it,
492 if necessary. */
493 gamedocdir = (char *)xmalloc(strlen(docdir) + 10 + strlen(curmodulename));
494 strcpy(gamedocdir, docdir);
495 strcat(gamedocdir, "/");
496 strcat(gamedocdir, curmodulename);
497 if (access(gamedocdir, F_OK)) {
498 mkdir(gamedocdir, 0755);
499 /* \TODO: Should handle any errors that result from this.\ */
500 }
501 /* Set help output directory. */
502 set_help_output_dir(gamedocdir);
503 /* Report the documentation's location. */
504 printf("Writing game docs to '%s'.\n", gamedocdir);
505 /* Initialize help system. */
506 init_help();
507 /* Write out all the help files for the current module. */
508 create_game_help_nodes();
509 }
510
511 void
run_ui_idler(void)512 run_ui_idler (void)
513 {}
514
515 Player *
add_default_player(void)516 add_default_player(void)
517 {
518 Player *dflt = add_player();
519
520 dflt->displayname = "stdio";
521 Dprintf("Added the default player %s\n", player_desig(dflt));
522 return dflt;
523 }
524
525 void
make_default_player_spec(void)526 make_default_player_spec(void)
527 {
528 default_player_spec = "stdio";
529 }
530
531 /* Create a user interface, but leave it turned off. */
532
533 void
init_ui(Side * side)534 init_ui(Side *side)
535 {
536 if (side_wants_display(side)) {
537 side->ui = (UI *) xmalloc(sizeof(UI));
538 /* Display should not become active yet. */
539 side->ui->active = FALSE;
540 defaultside = side;
541 /* Do this so game doesn't run out of control. */
542 net_set_autofinish(side, FALSE);
543 DGprintf("Created a UI for %s\n", side_desig(side));
544 } else {
545 side->ui = NULL;
546 }
547 }
548
549 /* This tests whether the side has a display and if it is in use. */
550
551 int
active_display(Side * side)552 active_display(Side *side)
553 {
554 return (side && side_has_display(side) && side->ui->active);
555 }
556
557 /* Shut down displays - should be done before any sort of exit. */
558
559 void
close_displays(void)560 close_displays(void)
561 {
562 Side *side;
563
564 for_all_sides(side) {
565 if (active_display(side)) {
566 side->ui->active = FALSE;
567 printf("Display \"%s\" closed.\n", side->player->displayname);
568 }
569 }
570 }
571
572 void
cmd_error(Side * side,char * fmt,...)573 cmd_error(Side *side, char *fmt, ...)
574 {
575 char tmpnbuf[BUFSIZE];
576 va_list ap;
577
578 if (!empty_string(fmt)) {
579
580 va_start(ap, fmt);
581 vsnprintf(tmpnbuf, sizeof tmpnbuf, fmt, ap);
582 va_end(ap);
583
584 low_notify(dside, tmpnbuf);
585 }
586 }
587
588 void
low_notify(Side * side,char * str)589 low_notify(Side *side, char *str)
590 {
591 printf("To %s: %s\n", side_desig(side), str);
592 }
593
594 void
update_area_display(Side * side)595 update_area_display(Side *side)
596 {
597 }
598
599 void
update_cell_display(Side * side,int x,int y,int flags)600 update_cell_display(Side *side, int x, int y, int flags)
601 {
602 }
603
604 void
update_turn_display(Side * side,int rightnow)605 update_turn_display(Side *side, int rightnow)
606 {
607 }
608
609 void
update_action_display(Side * side,int rightnow)610 update_action_display(Side *side, int rightnow)
611 {
612 if (active_display(side) && DebugG) {
613 printf("Update %s: ready to act\n", side_desig(side));
614 }
615 }
616
617 void
update_action_result_display(Side * side,Unit * unit,int rslt,int rightnow)618 update_action_result_display(Side *side, Unit *unit, int rslt, int rightnow)
619 {
620 if (active_display(side) && DebugG) {
621 printf("Update %s: %s action result is %s\n",
622 side_desig(side), unit_desig(unit), hevtdefns[rslt].name);
623 }
624 }
625
626 /* This is for animation of fire-at actions. */
627
628 void
update_fire_at_display(Side * side,Unit * unit,Unit * unit2,int m,int rightnow)629 update_fire_at_display(Side *side, Unit *unit, Unit *unit2, int m, int rightnow)
630 {
631 if (active_display(side) && DebugG) {
632 printf("Update %s: %s fire at %s\n",
633 side_desig(side), unit_desig(unit), unit_desig(unit2));
634 }
635 }
636
637 /* This is for animation of fire-into actions. */
638
639 void
update_fire_into_display(Side * side,Unit * unit,int x,int y,int z,int m,int rightnow)640 update_fire_into_display(Side *side, Unit *unit, int x, int y, int z, int m,
641 int rightnow)
642 {
643 if (active_display(side) && DebugG) {
644 printf("Update %s: %s fire into %d,%d\n",
645 side_desig(side), unit_desig(unit), x, y);
646 }
647 }
648
649 void
update_event_display(Side * side,HistEvent * hevt,int rightnow)650 update_event_display(Side *side, HistEvent *hevt, int rightnow)
651 {
652 if (active_display(side)) {
653 switch (hevt->type) {
654 case H_SIDE_LOST:
655 printf("%s lost!\n", side_desig(side_n(hevt->data[0])));
656 break;
657 case H_SIDE_WON:
658 printf("%s won!\n", side_desig(side_n(hevt->data[0])));
659 break;
660 default:
661 DGprintf("Update %s: event %s %d\n",
662 side_desig(side), hevtdefns[hevt->type].name,
663 hevt->data[0]);
664 }
665 }
666 }
667
668 void
update_all_progress_displays(char * str,int s)669 update_all_progress_displays(char *str, int s)
670 {
671 if (DebugG) {
672 printf("Update all progress displays\n");
673 }
674 }
675
676 /* This hook should update the side's view of the given side, no matter
677 who it belongs to. */
678
679 void
update_side_display(Side * side,Side * side2,int rightnow)680 update_side_display(Side *side, Side *side2, int rightnow)
681 {
682 char *side2desc = copy_string(side_desig(side2));
683
684 if (active_display(side) && DebugG) {
685 printf("Update %s: side %s%s\n",
686 side_desig(side), side2desc, (rightnow ? " (now)" : ""));
687 }
688 }
689
690 void
update_research_display(Side * side)691 update_research_display(Side *side)
692 {
693 if (numatypes > 0
694 && g_side_can_research()
695 && dside->research_topic == NOADVANCE) {
696 /* Should eventually pop up a side research dialog instead. */
697 auto_pick_side_research(dside);
698 }
699 }
700
701 /* This hook should update the side's view of the given unit, no matter
702 who it belongs to. */
703
704 void
update_unit_display(Side * side,Unit * unit,int rightnow)705 update_unit_display(Side *side, Unit *unit, int rightnow)
706 {
707 if (active_display(side) && DebugG) {
708 printf("Update %s: unit %s%s\n",
709 side_desig(side), unit_desig(unit), (rightnow ? " (now)" : ""));
710 }
711 }
712
713 void
update_unit_acp_display(Side * side,Unit * unit,int rightnow)714 update_unit_acp_display(Side *side, Unit *unit, int rightnow)
715 {
716 if (active_display(side) && DebugG) {
717 printf("Update %s: unit %s acp%s\n",
718 side_desig(side), unit_desig(unit), (rightnow ? " (now)" : ""));
719 }
720 }
721
722 /* This hook updates any realtime clock displays. If the game does not
723 have any realtime constraints, this will never be called. */
724
725 void
update_clock_display(Side * side,int rightnow)726 update_clock_display(Side *side, int rightnow)
727 {
728 if (active_display(side) && DebugG) {
729 printf("Update %s: %d secs this turn, %d total\n",
730 side_desig(side), side->turntimeused, side->totaltimeused);
731 /* also display total game clock */
732 }
733 }
734
735 void
update_message_display(Side * side,Side * sender,char * str,int rightnow)736 update_message_display(Side *side, Side *sender, char *str, int rightnow)
737 {
738 if (active_display(side) && DebugG) {
739 printf("Update %s: side %d sends \"%s\"%s\n",
740 side_desig(side), side_number(sender), str, (rightnow ? " (now)" : ""));
741 }
742 }
743
744 void
update_everything(void)745 update_everything(void)
746 {
747 printf("Update everything!\n");
748 }
749
750 void
action_point(Side * side,int x,int y)751 action_point(Side *side, int x, int y)
752 {
753 }
754
755
756 /* This reports progress in reading GDL files. */
757
758 void
announce_read_progress(void)759 announce_read_progress(void)
760 {
761 }
762
763 /* This is used for initialization steps that take a long time. */
764
765 int linemiddle = FALSE;
766
767 void
announce_lengthy_process(char * msg)768 announce_lengthy_process(char *msg)
769 {
770 printf("%s; ", msg);
771 fflush(stdout);
772 linemiddle = TRUE;
773 }
774
775 /* Update the progress, expressing it as a percentage done. */
776
777 void
announce_progress(int percentdone)778 announce_progress(int percentdone)
779 {
780 printf(" %d%%", percentdone);
781 fflush(stdout);
782 linemiddle = TRUE;
783 }
784
785 /* Announce the end of the lengthy process. */
786
787 void
finish_lengthy_process(void)788 finish_lengthy_process(void)
789 {
790 printf(" done.\n");
791 linemiddle = FALSE;
792 }
793
794 int
schedule_movie(Side * side,char * movie,...)795 schedule_movie(Side *side, char *movie, ...)
796 {
797 return FALSE;
798 }
799
800 void
play_movies(SideMask sidemask)801 play_movies(SideMask sidemask)
802 {
803 }
804
805 void
flush_display_buffers(Side * side)806 flush_display_buffers(Side *side)
807 {
808 if (active_display(side) && DebugG) {
809 printf("To %s: flush display buffers\n", side_desig(side));
810 }
811 }
812
813 /* An init error needs to have the command re-run. */
814
815 void
low_init_error(char * str)816 low_init_error(char *str)
817 {
818 if (linemiddle)
819 printf("\n");
820 fprintf(stderr, "%s Error: %s.\n", (mainmodule ? mainmodule->name : ""),
821 str);
822 fflush(stderr);
823 }
824
825 static void
report_warning(void)826 report_warning(void)
827 {
828 /* Ideally this would get passed back to the test framework which could
829 record it as FAIL or ERROR, but for now just make sure it doesn't
830 score as PASS. */
831 exit(EXIT_FAILURE);
832 }
833
834 /* A warning just gets displayed, no other action is taken. */
835
836 void
low_init_warning(char * str)837 low_init_warning(char *str)
838 {
839 if (linemiddle)
840 printf("\n");
841 fprintf(stdout, "%s Warning: %s.\n", (mainmodule ? mainmodule->name : ""),
842 str);
843 fflush(stdout);
844
845 report_warning();
846 }
847
848 /* A run error is fatal. */
849
850 void
low_run_error(char * str)851 low_run_error(char *str)
852 {
853 if (linemiddle)
854 fprintf(stderr, "\n");
855 fprintf(stderr, "%s Error: %s.\n", (mainmodule ? mainmodule->name : ""),
856 str);
857 fflush(stderr);
858 exit(1);
859 }
860
861 /* Runtime warnings are for when it's important to bug the players,
862 usually a problem with Xconq or a game design. */
863
864 void
low_run_warning(char * str)865 low_run_warning(char *str)
866 {
867 if (linemiddle)
868 printf("\n");
869 fprintf(stdout, "%s Warning: %s.\n", (mainmodule ? mainmodule->name : ""),
870 str);
871 fflush(stdout);
872 report_warning();
873 }
874
875 void
print_form(Obj * form)876 print_form(Obj *form)
877 {
878 print_form_and_value(stdout, form);
879 }
880
881 void
end_printing_forms(void)882 end_printing_forms(void)
883 {
884 }
885
886 void
make_generic_image_data(ImageFamily * imf)887 make_generic_image_data(ImageFamily *imf)
888 {
889 }
890
891 #ifdef MAC
892
893 int current_cursor;
894 int receivecursor;
895 int sendcursor;
896
897 #endif /* MAC */
898
899 void
unit_research_dialog(Unit * unit)900 unit_research_dialog(Unit *unit)
901 {
902 auto_pick_unit_research(unit);
903 }
904
905 void
add_remote_locally(int rid,char * str)906 add_remote_locally(int rid, char *str)
907 {
908 }
909
910 void
send_chat(int rid,char * str)911 send_chat(int rid, char *str)
912 {
913 printf("From %d: received chat \"%s\"\n", rid, str);
914 }
915
916 /* Dummy function needed in run_turn_start. */
917
918 void
place_legends(Side * side)919 place_legends(Side *side)
920 {
921 }
922