1 /* Command line parsing for Xconq.
2    Copyright (C) 1987-1989, 1991-2000 Stanley T. Shebs.
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 is a command-line parser that may be used in implementations
10    that get a command line from somewhere. */
11 
12 /* Command lines get parsed in several stages, since for instance the
13    choice of game module will decide which variants are available. */
14 
15 #include "conq.h"
16 extern short initially_no_ai;
17 #include "kpublic.h"
18 #include "cmdline.h"
19 
20 static void add_a_raw_player_spec(char *specstr);
21 static void version_info(void);
22 static void general_usage_info(void);
23 static void game_usage_info(void);
24 static void player_usage_info(void);
25 static void parse_world_option(char *str);
26 static void parse_realtime_option(char *subopt, char *arg);
27 static void parse_variant(char *str);
28 static int find_variant_from_name(Module *module, char *name);
29 
30 /* The startup-settable options. */
31 
32 static int option_width;
33 static int option_height;
34 static int option_circumference;
35 static int option_total_game_time;
36 static int option_per_side_time;
37 static int option_per_turn_time;
38 static int option_add_default_player;
39 
40 char *option_game_to_host = NULL;
41 
42 char *option_game_to_join = NULL;
43 
44 int option_num_to_wait_for = 0;
45 
46 static char *default_ai_type = ",mplayer";
47 
48 /* Use this to record the options used to set up a game, so it can be
49    reported to users. */
50 /* (should flush? better to display in intelligible form) */
51 
52 char *args_used;
53 
54 /* The list of asked-for players. */
55 
56 struct raw_spec {
57   char *spec;
58   struct raw_spec *next;
59 } *raw_player_specs, *last_raw_player_spec;
60 
61 char *raw_default_player_spec;
62 
63 /* The list of accumulated variant choices. */
64 
65 static Obj *variant_settings;
66 
67 static char *program_name = "";
68 
69 static int help_wanted = FALSE;
70 
71 static int variant_help_wanted = FALSE;
72 
73 static int version_wanted = FALSE;
74 
75 static int had_error = FALSE;
76 
77 /* Set the most basic of defaults on the dynamically-settable
78    options. */
79 
80 /* (need flags to indicate which options were actually used, so
81    variant handling can warn about improper use) */
82 
83 void
init_options(void)84 init_options(void)
85 {
86     option_add_default_player = TRUE;
87     variant_settings = lispnil;
88 }
89 
90 /* Generic command line parsing.  This is used by several different
91    programs, so it just collects info, doesn't process it much.  This
92    is called several times, because the validity of some args depends
93    on which game modules are loaded and which players are to be in the
94    game, and interfaces may need to do some of their own processing in
95    between. */
96 
97 void
parse_command_line(int argc,char * argv[],int spec)98 parse_command_line(int argc, char *argv[], int spec)
99 {
100     char *arg, *aispec, tmpspec[100], tmpargbuf[CLIBUFSIZE], blurb[BLURBSIZE];
101     int i, n, numused, total_arg_space, tmpargbuflen = 0;
102 
103 /* This macro just checks that a required next argument is actually
104    there. */
105 
106 #define REQUIRE_ONE_ARG  \
107   if (i + 1 >= argc) {  \
108     fprintf(stderr, "Error: `%s' requires an argument, exiting now\n", argv[i]);  \
109     had_error = TRUE;  \
110     continue;  \
111   }  \
112   numused = 2;
113 
114 /* Each of these causes argument parsing to skip over the option if
115    it's not the right time to look at it. */
116 
117 #define GENERAL_OPTION if (spec != general_options) continue;
118 #define VARIANT_OPTION if (spec != variant_options) continue;
119 #define PLAYER_OPTION  if (spec != player_options)  continue;
120 
121     /* (should peel off any path stuff) */
122     program_name = argv[0];
123 
124     if (spec == general_options)
125       init_options();
126 
127     total_arg_space = 0;
128     for (i = 0; i < argc; ++i) {
129       if (!empty_string(argv[i])) {
130         strncpy(tmpargbuf, argv[i], CLIBUFSIZE);
131         tmpargbuf[CLIBUFSIZE - 1] = 0;
132         tmpargbuflen = strlen(tmpargbuf);
133 	total_arg_space += tmpargbuflen + 2;
134         (argv[i])[tmpargbuflen] = 0;
135       }
136     }
137     if (args_used == NULL)
138       args_used = (char *)xmalloc (total_arg_space);
139 
140     for (i = 1; i < argc; ++i) {
141 	if (argv[i] == NULL || (argv[i])[0] == '\0') {
142 	    /* Empty or already munched, nothing to do. */
143 	} else if ((argv[i])[0] == '-') {
144 	    arg = argv[i];
145 	    Dprintf("%s\n", arg);
146 	    numused = 1;
147 	    if (strcmp(arg, "-c") == 0) {
148 		REQUIRE_ONE_ARG;
149 		GENERAL_OPTION;
150 		checkpoint_interval = atoi(argv[i+1]);
151 	    } else if (strcmp(arg, "-design") == 0) {
152 		GENERAL_OPTION;
153 #ifdef DESIGNERS
154 		allbedesigners = TRUE;
155 #else
156 		fprintf(stderr,
157 			"No designing available, ignoring option `%s'\n", arg);
158 #endif /* DESIGNERS */
159 	    } else if (strncmp(arg, "-D", 2) == 0) {
160 		GENERAL_OPTION;
161 #ifdef DEBUGGING
162 		Debug = TRUE;
163 		if (strchr(arg+2, '-'))
164 		  Debug = FALSE;
165 		if (strchr(arg+2, 'M'))
166 		  DebugM = TRUE;
167 		if (strchr(arg+2, 'G'))
168 		  DebugG = TRUE;
169 #else
170 		fprintf(stderr,
171 			"No debugging available, ignoring option `%s'\n", arg);
172 #endif /* DEBUGGING */
173 	    } else if (strncmp(arg, "-e", 2) == 0) {
174 		REQUIRE_ONE_ARG;
175 		PLAYER_OPTION;
176 		n = atoi(argv[i+1]);
177 		/* A comma indicates that the name of a particular
178 		   desired AI type follows. */
179 		if (strlen(arg) > 2) {
180 		    aispec = arg + 2;
181 		    if (*aispec != ',') {
182 			sprintf(tmpspec, "%s%s", default_ai_type, aispec);
183 			aispec = tmpspec;
184 		    }
185 		} else {
186 		    aispec = default_ai_type;
187 		}
188 		while (n-- > 0)
189 		  add_a_raw_player_spec(aispec);
190 	    } else if (strcmp(arg, "-f") == 0) {
191 		REQUIRE_ONE_ARG;
192 		GENERAL_OPTION;
193 		add_a_module(NULL, argv[i+1]);
194 	    } else if (strcmp(arg, "-g") == 0) {
195 		REQUIRE_ONE_ARG;
196 		GENERAL_OPTION;
197 		add_a_module(copy_string(argv[i+1]), NULL);
198 	    } else if (strcmp(arg, "-h") == 0) {
199 		REQUIRE_ONE_ARG;
200 		PLAYER_OPTION;
201 		n = atoi(argv[i+1]);
202 		option_num_to_wait_for += n;
203 		while (n-- > 0)
204 		  add_a_raw_player_spec("?@");
205 	    } else if (strcmp(arg, "-help") == 0) {
206 		GENERAL_OPTION;
207 		help_wanted = TRUE;
208 		/* Will display help info later. */
209 	    } else if (strcmp(arg, "-host") == 0) {
210 		REQUIRE_ONE_ARG;
211 		GENERAL_OPTION;
212 		option_game_to_host = copy_string(argv[i+1]);
213 	    } else if (strcmp(arg, "-join") == 0) {
214 		REQUIRE_ONE_ARG;
215 		GENERAL_OPTION;
216 		option_game_to_join = copy_string(argv[i+1]);
217 	    } else if (strcmp(arg, "-L") == 0) {
218 		REQUIRE_ONE_ARG;
219 		GENERAL_OPTION;
220 		if (strcmp(argv[i+1], "-") == 0)
221 		  add_library_path(NULL);
222 		else
223 		  add_library_path(argv[i+1]);
224 	    } else if (strcmp(arg, "-M") == 0) {
225 		REQUIRE_ONE_ARG;
226 		VARIANT_OPTION;
227 		parse_world_option(argv[i+1]);
228 	    } else if (strcmp(arg, "-noai") == 0) {
229 		PLAYER_OPTION;
230 		initially_no_ai = TRUE;
231 	    } else if (strcmp(arg, "-r") == 0) {
232 		PLAYER_OPTION;
233 		option_add_default_player = FALSE;
234 	    } else if (strcmp(arg, "-R") == 0) {
235 		REQUIRE_ONE_ARG;
236 		GENERAL_OPTION;
237 #ifdef DEBUGGING
238 		init_xrandom(atoi(argv[i+1]));
239 #else
240 		fprintf(stderr,
241 			"No debugging available, ignoring option `%s'\n", arg);
242 #endif /* DEBUGGING */
243 	    } else if (strcmp(arg, "-seq") == 0) {
244 		VARIANT_OPTION;
245 		push_key_int_binding(&variant_settings, K_SEQUENTIAL, 1);
246 	    } else if (strcmp(arg, "-sim") == 0) {
247 		VARIANT_OPTION;
248 		push_key_int_binding(&variant_settings, K_SEQUENTIAL, 0);
249 	    } else if (strncmp(arg, "-t", 2) == 0) {
250 		REQUIRE_ONE_ARG;
251 		VARIANT_OPTION;
252 		parse_realtime_option(arg, argv[i+1]);
253 	    } else if (strncmp(arg, "-v", 2) == 0) {
254 		VARIANT_OPTION;
255 		parse_variant(arg + 2);
256 	    } else if (strcmp(arg, "-V") == 0) {
257 		VARIANT_OPTION;
258 		push_key_int_binding(&variant_settings, K_SEE_ALL, 1);
259 	    } else if (strcmp(arg, "-V0") == 0) {
260 		VARIANT_OPTION;
261 		push_key_int_binding(&variant_settings, K_SEE_ALL, 0);
262 	    } else if (strcmp(arg, "-Vfalse") == 0) {
263 		VARIANT_OPTION;
264 		push_key_int_binding(&variant_settings, K_SEE_ALL, 0);
265 	    } else if (strcmp(arg, "-w") == 0) {
266 		GENERAL_OPTION;
267 		warnings_suppressed = TRUE;
268 	    } else if (strcmp(arg, "-x") == 0) {
269 		GENERAL_OPTION;
270 		option_popup_new_game_dialog = TRUE;
271 	    } else if (strcmp(arg, "--help") == 0) {
272 		GENERAL_OPTION;
273 		help_wanted = TRUE;
274 		/* Will display help info later. */
275 	    } else if (strcmp(arg, "--version") == 0) {
276 		GENERAL_OPTION;
277 		version_wanted = TRUE;
278 	    } else {
279 		numused = 0;
280 		/* Anything unrecognized during the last parse is an error. */
281 		if (spec >= leftover_options) {
282 		    fprintf(stderr, "Unrecognized option `%s'\n", arg);
283 		    had_error = TRUE;
284 		}
285 	    }
286 	    if (numused >= 1) {
287 		strcat(args_used, " ");
288 		strcat(args_used, argv[i]);
289 		argv[i] = "";
290 	    }
291 	    if (numused >= 2) {
292 		strcat(args_used, " ");
293 		strcat(args_used, argv[i+1]);
294 		argv[i+1] = "";
295 	    }
296 	    if (numused >= 1)
297 	      i += (numused - 1);
298 	} else {
299 	    if (spec == player_options) {
300 		if (*(argv[i]) == '+' || *(argv[i]) == '@') {
301 		    raw_default_player_spec = argv[i];
302 		} else {
303 		    add_a_raw_player_spec(argv[i]);
304 		}
305 		strcat(args_used, " ");
306 		strcat(args_used, argv[i]);
307 		argv[i] = NULL;
308 	    }
309 	}
310     }
311     if (version_wanted) {
312 	version_info();
313     }
314     if (had_error || help_wanted || variant_help_wanted) {
315 	/* If we want to get help about a particular game, have to
316            load it first. */
317 	if (help_wanted || variant_help_wanted)
318 	  load_all_modules();
319 	if (had_error || help_wanted)
320 	  general_usage_info();
321 	if (had_error || help_wanted)
322 	  player_usage_info();
323 	if (help_wanted && mainmodule != NULL) {
324 	    printf("\nGame info:\n\n");
325 	    if (!empty_string(mainmodule->title))
326 	      printf("%s (%s)\n", mainmodule->title, mainmodule->name);
327 	    else
328 	      printf("%s\n", mainmodule->name);
329 	    printf("    %s\n");
330 	    if (mainmodule->blurb != lispnil) {
331 	    	append_blurb_strings(blurb, mainmodule->blurb);
332 	    	printf("%s", blurb);
333 	    } else {
334 	    	printf("(no description)");
335 	    }
336 	}
337 	/* Display variant info here so it comes after basic info
338 	   about the game module. */
339 	if (had_error || help_wanted || variant_help_wanted)
340 	  game_usage_info();
341     }
342     if (had_error || help_wanted || variant_help_wanted || version_wanted) {
343 	exit(had_error);
344     }
345 }
346 
347 /* Given a module name and/or filename, add it to the list of modules
348    to load. */
349 
350 void
add_a_module(char * name,char * filename)351 add_a_module(char *name, char *filename)
352 {
353     Module *module;
354 
355     module = get_game_module(name);
356     if (module == NULL)
357       exit(1);  /* bad error if happens */
358     if (filename)
359       module->filename = copy_string(filename);
360     if (mainmodule != NULL)
361       printf("Warning: game module already specified, will replace");
362     mainmodule = module;
363 }
364 
365 /* Glue an unprocessed player spec onto the list of other specs found
366    on the command line. */
367 
368 static void
add_a_raw_player_spec(char * specstr)369 add_a_raw_player_spec(char *specstr)
370 {
371     struct raw_spec *spec =
372       (struct raw_spec *) xmalloc (sizeof(struct raw_spec));
373 
374     spec->spec = copy_string(specstr);
375     if (raw_player_specs == NULL)
376       raw_player_specs = spec;
377     else
378       last_raw_player_spec->next = spec;
379     last_raw_player_spec = spec;
380 }
381 
382 static void
version_info(void)383 version_info(void)
384 {
385     printf("Xconq (%s) version %s\n", program_name, version_string());
386 }
387 
388 /* This routine prints out help info about all the possible arguments. */
389 
390 static void
general_usage_info(void)391 general_usage_info(void)
392 {
393     printf("Usage:\n\t%s [ -options ... ]\n\n", program_name);
394     printf("General options:\n\n");
395     printf("    -c n\t\tcheckpoint every <n> turns\n");
396     printf("    -f filename\t\trun <filename> as a game\n");
397     printf("    -g gamename\t\tfind <gamename> in library and run it\n");
398     printf("    -help\t\tdisplay this help info\n");
399     printf("    -host <game@host>\thost the given game\n");
400     printf("    -join <game@host>\tconnect to the given game\n");
401     printf("    -L pathname\t\tset <pathname> to be library location\n");
402     printf("    -w\t\t\tsuppress warnings\n");
403     printf("    -x\t\t\tuse game setup dialogs to choose game and options\n");
404     printf("    -design\t\tmake every player a designer");
405 #ifndef DESIGNERS
406     printf(" (not available)");
407 #endif
408     printf("\n");
409     /* We don't display the debugging options -D* and -R, on the
410        theory that only hackers should try to use them. */
411     /* Group the long options together, but don't identify them
412        specially. */
413     printf("    --help\t\tdisplay this help info\n");
414     printf("    --version\t\tdisplay version info\n");
415 }
416 
417 /* Describe the available variants for a game. */
418 
419 static void
game_usage_info(void)420 game_usage_info(void)
421 {
422     int i, wid, hgt, circumf, lat, lon, pergame, perside, perturn;
423     char *varid;
424     char buf[BUFSIZE];
425     Variant *var;
426     Obj *vardflt;
427 
428     printf("\nGame variant options");
429     if (mainmodule == NULL) {
430 	printf(":\n\n    No game loaded, no information available.\n\n");
431 	return;
432     }
433     printf(" for \"%s\":\n\n", mainmodule->name);
434     if (mainmodule->variants == NULL) {
435 	printf("    No variants available.\n\n");
436 	return;
437     }
438     for (i = 0; mainmodule->variants[i].id != lispnil; ++i) {
439 	var = &(mainmodule->variants[i]);
440 	varid = c_string(var->id);
441 	vardflt = var->dflt;
442 	switch (keyword_code(varid)) {
443 	  case K_SEE_ALL:
444 	    printf("    -V\t\t\t%s (default %s)\n",
445 		   var->help,
446 		   (vardflt == lispnil ? "true" :
447 		    (c_number(eval(vardflt)) ? "true" : "false")));
448 	    break;
449 	  case K_SEQUENTIAL:
450 	    printf("    -seq\t\t%s (default %s)\n",
451 		   var->help,
452 		   (vardflt == lispnil ? "false" :
453 		    (c_number(eval(vardflt)) ? "false" : "true")));
454 	    printf("    -sim\t\tSides move simultaneously (opposite of -seq)\n");
455 	    break;
456 	  case K_WORLD_SEEN:
457 	    printf("    -v\t\t\t%s (default %s)\n",
458 		   var->help,
459 		   (vardflt == lispnil ? "true" :
460 		    (c_number(eval(vardflt)) ? "true" : "false")));
461 	    break;
462 	  case K_WORLD_SIZE:
463 	    printf("    -M wid[xhgt][Wcircumf][+lat][+long]\tset world size (default ");
464 	    /* Note that if the game definition sets these values
465 	       directly using world or area forms, this is misleading;
466 	       but that's the fault of the game designer for including
467 	       both preset values and a variant whose defaults don't
468 	       match those presets. */
469 	    circumf = DEFAULTCIRCUMFERENCE;
470 	    wid = DEFAULTWIDTH;  hgt = DEFAULTHEIGHT;
471 	    lat = lon = 0;
472 	    /* Pick the width and height out of the list. */
473 	    if (vardflt != lispnil) {
474 		wid = c_number(eval(car(vardflt)));
475 		vardflt = cdr(vardflt);
476 	    }
477 	    if (vardflt != lispnil) {
478 		hgt = c_number(eval(car(vardflt)));
479 		vardflt = cdr(vardflt);
480 	    } else {
481 		hgt = wid;
482 	    }
483 	    /* Pick up a circumference etc if given. */
484 	    if (vardflt != lispnil) {
485 		circumf = c_number(eval(car(vardflt)));
486 		vardflt = cdr(vardflt);
487 	    }
488 	    if (vardflt != lispnil) {
489 		lat = c_number(eval(car(vardflt)));
490 		vardflt = cdr(vardflt);
491 	    }
492 	    if (vardflt != lispnil) {
493 		lon = c_number(eval(car(vardflt)));
494 	    }
495 	    printf("%dx%dW%d", wid, hgt, circumf);
496 	    if (lat != 0 || lon != 0)
497 	      printf("+%d+%d", lat, lon);
498 	    printf(")\n");
499 	    break;
500 	  case K_REAL_TIME:
501 	    pergame = perside = perturn = 0;
502 	    if (vardflt != lispnil) {
503 		pergame = c_number(eval(car(vardflt)));
504 		vardflt = cdr(vardflt);
505 	    }
506 	    if (vardflt != lispnil) {
507 		perside = c_number(eval(car(vardflt)));
508 		vardflt = cdr(vardflt);
509 	    }
510 	    if (vardflt != lispnil) {
511 		perturn = c_number(eval(car(vardflt)));
512 	    }
513 	    printf("    -tgame mins\t\tlimit game time to <mins> minutes (default %d)\n",
514 		   pergame);
515 	    printf("    -tside mins\t\tlimit each player <mins> minutes in all (default %d)\n",
516 		   perside);
517 	    printf("    -tturn mins\t\tlimit each turn to <mins> minutes (default %d)\n",
518 		   perturn);
519 	    break;
520 	  default:
521 	    printf("    -v%s[=value]\t%s (default ", varid, var->help);
522 	    if (vardflt == lispnil
523 	        || (numberp(vardflt) && c_number(vardflt) == 0)) {
524 		printf("false");
525 	    } else if (numberp(vardflt) && c_number(vardflt) == 1) {
526 		printf("true");
527 	    } else {
528 		sprintlisp(buf, vardflt, BUFSIZE);
529 		printf("%s", buf);
530 	    }
531 	    printf(")\n");
532 	    break;
533 	}
534     }
535 }
536 
537 /* Dump info about player setup options.  These can only get used when
538    the game has been loaded and variants chosen. */
539 
540 static void
player_usage_info(void)541 player_usage_info(void)
542 {
543     printf("\nPlayer setup options:\n\n");
544     printf("    [[name][,ai][/config]@]host[+advantage]\tadd player\n");
545     printf("        ai\t\t= name of AI type or \"ai\" for default type\n");
546     printf("        config\t\t= name of config file\n");
547     printf("        host\t\t= name of player's host machine or display\n");
548     printf("        advantage\t= numerical initial advantage (default 1)\n");
549     printf("    -e number[,ai]\tadd <number> computer players\n");
550     printf("    -h number[,ai]\tadd <number> human players\n");
551     printf("    -noai\t\tsuppress all AIs\n");
552     printf("    -r\t\t\tno default player on local display\n");
553     /* (should available AI types here) */
554 }
555 
556 /* Given a string representing world dimensions, extract various
557    components. */
558 
559 static void
parse_world_option(char * str)560 parse_world_option(char *str)
561 {
562     char *str2;
563 
564     option_width = atoi(str);
565     option_height = option_width;
566     str2 = strchr(str, 'x');
567     if (str2 != NULL)
568       option_height = atoi(str2 + 1);
569     /* Add a world circumference setting if present. */
570     str2 = strchr(str, 'W');
571     if (str2 != NULL)
572       option_circumference = atoi(str2 + 1);
573 }
574 
575 static void
parse_realtime_option(char * subopt,char * arg)576 parse_realtime_option(char *subopt, char *arg)
577 {
578     if (strcmp(subopt, "-tgame") == 0) {
579 	option_total_game_time = 60 * atoi(arg);
580     } else if (strcmp(subopt, "-tside") == 0) {
581 	option_per_side_time = 60 * atoi(arg);
582     } else if (strcmp(subopt, "-tturn") == 0) {
583 	option_per_turn_time = 60 * atoi(arg);
584     } else {
585 	fprintf(stderr, "Realtime option not one of -tgame, -tside, -tturn, ignoring\n");
586     }
587 }
588 
589 /* Given a variant, turn it into a list "(name val)". */
590 
591 static void
parse_variant(char * str)592 parse_variant(char *str)
593 {
594     char *varname = NULL, *str2;
595     Obj *varval = lispnil;
596 
597     if (strcmp(str, "") == 0) {
598 	push_key_int_binding(&variant_settings, K_WORLD_SEEN, 1);
599     } else if (strcmp(str, "help") == 0) {
600 	variant_help_wanted = TRUE;
601     } else {
602 	str2 = strchr(str, '=');
603 	if (str2 != NULL && str2 != str) {
604 	    /* (should interp val as string or number) */
605 	    varval = new_number(atoi(str2 + 1));
606 	    varname = copy_string(str);
607 	    varname[str2 - str] = '\0';
608 	} else {
609 	    /* Assume varname by itself means "enable" (set to value of 1). */
610 	    varname = str;
611 	    varval = new_number(1);
612 	}
613 	if (varname)
614 	  push_binding(&variant_settings, intern_symbol(varname), varval);
615     }
616 }
617 
618 /* Load the game module asked for on the cmd line, or else the
619    default. */
620 
621 void
load_all_modules(void)622 load_all_modules(void)
623 {
624     if (mainmodule != NULL) {
625 	load_game_module(mainmodule, TRUE);
626     } else {
627 	/* If we've got absolutely no files to load, the standard game
628 	   is the one to go for.  It will direct the remainder of
629 	   random generation. */
630 	load_default_game();
631     }
632 }
633 
634 /* Set module variants from command line options. */
635 
636 void
set_variants_from_options(void)637 set_variants_from_options(void)
638 {
639     int which;
640     char *varname;
641     Obj *varrest, *varset;
642 
643     /* Only the host of a networked game can set variants. */
644     if (option_game_to_join != NULL) {
645 	if (variant_settings != lispnil
646 	    || option_width > 0)
647 	  fprintf(stderr, "Not the host, ignoring variant settings\n");
648 	return;
649     }
650     if (option_width > 0) {
651 	which = find_variant_from_name(mainmodule, keyword_name(K_WORLD_SIZE));
652 	if (which >= 0)
653 	  net_set_variant_value(which, option_width, option_height,
654 				option_circumference);
655 	else
656 	  fprintf(stderr, "World size variant not available, -M ignored\n");
657     }
658     /* Set the real-time variant if any times were supplied. */
659     if (option_total_game_time != 0
660 	|| option_per_side_time != 0
661 	|| option_per_turn_time != 0) {
662 	which = find_variant_from_name(mainmodule, keyword_name(K_REAL_TIME));
663 	if (which >= 0)
664 	  net_set_variant_value(which, option_total_game_time,
665 				option_per_side_time, option_per_turn_time);
666 	else
667 	  fprintf(stderr, "Real time variants not available, ignored\n");
668     }
669     for_all_list(variant_settings, varrest) {
670 	varset = car(varrest);
671 	varname = c_string(car(varset));
672 	which = find_variant_from_name(mainmodule, varname);
673 	if (which >= 0)
674 	  net_set_variant_value(which, c_number(cadr(varset)), 0, 0);
675 	else
676 	  fprintf(stderr, "No variant `%s' known, ignored\n", varname);
677     }
678     do_module_variants(mainmodule, lispnil);
679 }
680 
681 /* Given a string, return the index of the variant for the module, or
682    -1 to indicate that it is not the name of a valid variant. */
683 
684 static int
find_variant_from_name(Module * module,char * name)685 find_variant_from_name(Module *module, char *name)
686 {
687     int i;
688     Variant *var;
689 
690     if (module->variants == NULL)
691       return -1;
692     for (i = 0; module->variants[i].id != lispnil; ++i) {
693 	var = &(module->variants[i]);
694 	if (strcmp(name, c_string(var->id)) == 0)
695 	  return i;
696     }
697     return -1;
698 }
699 
700 /* Set player characteristics from command-line options. */
701 
702 void
set_players_from_options(void)703 set_players_from_options(void)
704 {
705     int mergespecs;
706     Player *player;
707     struct raw_spec *spec;
708 
709     /* Only the host of a networked game can set up players. */
710     if (option_game_to_join != NULL) {
711 	make_default_player_spec();
712 	return;
713     }
714     player = NULL;
715     /* Assume that if any players exist already, then this is a restored
716        game of some sort, and merge instead of adding new players. */
717     mergespecs = (numplayers > 0);
718     /* Add a player for the indepside if none found. */
719     if (indepside_needed() && find_player(0) == NULL)
720       player = add_player();
721     /* If we're merging specs, skip over the indepside player. */
722     if (mergespecs)
723       player = playerlist->next;
724     /* Add the default player. */
725     if (option_game_to_host == NULL
726 	&& (raw_player_specs == NULL || option_add_default_player)) {
727 	if (!mergespecs)
728 	  player = add_default_player();
729 	parse_player_spec(player, raw_default_player_spec);
730 	canonicalize_player(player);
731 	if (player)
732 	  player = player->next;
733     }
734     /* Add the explicitly listed players. */
735     for (spec = raw_player_specs; spec != NULL; spec = spec->next) {
736 	if (mergespecs) {
737 	    if (player == NULL) {
738 		fprintf(stderr, "Excess player spec `%s', ignoring\n",
739 			spec->spec);
740 		continue;
741 	    }
742 	} else {
743 	    player = add_player();
744 	}
745 	parse_player_spec(player, spec->spec);
746 	canonicalize_player(player);
747 	player = player->next;
748     }
749     /* If we made a special request to suppress AIs, go through all
750        players existing at this time. */
751     if (initially_no_ai) {
752 	for_all_players(player) {
753 	    player->aitypename = NULL;
754 	}
755     }
756     /* Transmit the official list of players to everybody else. */
757     if (my_rid > 0 && my_rid == master_rid) {
758 	for_all_players(player) {
759 	    net_update_player(player);
760 	}
761     }
762 }
763 
764 /* This is not, strictly speaking, part of command line processing,
765    but command-line programs are also the ones for which stdio is
766    useful. */
767 
768 void
print_instructions(void)769 print_instructions(void)
770 {
771     Obj *instructions, *rest;
772 
773     printf("\n");
774     if (mainmodule != NULL
775 	&& (instructions = mainmodule->instructions) != lispnil) {
776 	if (stringp(instructions)) {
777 	    printf("%s\n", c_string(instructions));
778 	} else if (consp(instructions)) {
779 	    for_all_list(instructions, rest) {
780 		if (stringp(car(rest))) {
781 		    printf("%s\n", c_string(car(rest)));
782 		} else {
783 		    run_warning("Instructions are of wrong type");
784 		}
785 	    }
786 	} else {
787 	    run_warning("Instructions are of wrong type");
788 	}
789     } else {
790 	printf("(no instructions supplied)\n");
791     }
792 }
793