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