1 /* pMARS -- a portable Memory Array Redcode Simulator
2 * Copyright (C) 1993-1996 Albert Ma, Na'ndor Sieben, Stefan Strack and Mintardjo Wangsawidjaja
3 * Copyright (C) 2000 Ilmari Karonen
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * clparse.c: command line parser
22 * $Id: clparse.c,v 1.5 2000/12/25 00:49:08 iltzu Exp $
23 */
24
25 /*******************************************************************
26 * *
27 * int parse_param(int argc,char *argv[]) *
28 * *
29 * Command line parameter parse *
30 * *
31 * if filename# exists then warrior[#].filename contains *
32 * the filename otherwise it contains NULL *
33 * number of warriors in warrior *
34 * *
35 * returns 0 if it's successfull *
36 * if there is an error in the command line it gives an *
37 * error message and returns a non-zero value (exit neccessary) *
38 * *
39 *******************************************************************/
40
41 #include <string.h>
42 #include <ctype.h>
43 #include "global.h"
44
45 #define CLP_MAXSTRLEN 80
46 #define CLP_ADDR ADDR_T
47 #define CLP_LONG long
48 #define CLP_INT int
49
50 typedef enum {
51 clp_int, clp_addr, clp_long, clp_bool, clp_str
52 } clp_dtype_t;
53
54 typedef struct clp_option_struct {
55 char word; /* sign for the switch */
56 pointer_t storage;
57 CLP_LONG min;
58 CLP_LONG max;
59 CLP_LONG def;
60 clp_dtype_t dtype;
61 char *description;
62 } clp_opt_t;
63
64 /* externalized strings */
65
66 extern char *credits_screen1, *credits_screen2, *credits_screen3, *usage_screen,
67 *optionsAre, *readingStdin, *readOptionsFromFile, *standardInput,
68 *errorIsLocatedIn, *unknownOption, *badArgumentForSwitch, *optionMustBeInTheRange, *tooManyParameters,
69 *cannotOpenParameterFile, *optRounds, *optEnterDebugger, *optDisabledInServerVersion,
70 *optCoreSize, *optBrief, *optCycles, *optVerboseAssembly, *optProcesses,
71 *optKotH, *optLength, *opt88, *optDistance, *optFixedSeries, *optFixedPosition,
72 *optSort, *optView, *optScoreFormula, *optDIAOutput, *noWarriorFile,
73 *fFExclusive, *coreSizeTooSmall, *dLessThanl, *FLessThand,
74 *outOfMemory, *badScoreFormula, *optPSpaceSize, *pSpaceTooBig,
75 *optPermutate, *permutateMultiWarrior;
76
77 #if defined(XWINGRAPHX)
78 extern char *badArgumentForXSwitch, *optXOpt[];
79 #endif
80
81 #ifdef MACGRAPHX
82 void
83 macputs(char *outputstr);
84 #endif
85
86 #ifdef NEW_STYLE
87 void
88 strip(char *argv[]);
89 void
90 print_usage(clp_opt_t clopt[]);
91 int
92 clp_parse(clp_opt_t clopt[],
93 FILE * filep);
94 int
95 parse_param(int argc, char **argv);
96 int
97 next_input(FILE * filep, char *inputs);
98
99 #else
100 void print_usage();
101 int next_input();
102 int clp_parse();
103 int parse_param();
104
105 #endif
106
107 static char *describe[] = {"#", "#", "#", " ", "$"};
108
109 #define record(pword,pdtype,pstorage,pmin,pmax,pdef,pdescription)\
110 options[optI].word = pword; \
111 options[optI].dtype = pdtype; \
112 options[optI].storage = (pointer_t) pstorage; \
113 options[optI].min = (CLP_LONG) pmin; \
114 options[optI].max = (CLP_LONG) pmax; \
115 options[optI].def = (CLP_LONG) pdef; \
116 options[optI++].description = pdescription
117
118 static char outs[MAXALLCHAR];
119 static int printed_usage; /* to show the help screen only once */
120 int argc;
121 char **argv;
122
123 /*******************************************************************
124 * credits and usage screen are now in str_???.c *
125 *******************************************************************/
126
127 #if defined (XWINGRAPHX)
128
129 /*********************************************
130 * check for standard X command line options *
131 *********************************************/
132
133 extern char *xOptions[];
134 extern char *xStorage[];
135 extern int xMaxOptions;
136
137 static clp_opt_t xOpt;
138
139 int
xwin_decode(inputs,clip)140 xwin_decode(inputs, clip)
141 char *inputs;
142 clp_opt_t **clip;
143 {
144 int i;
145
146 if (inputs[0] != '-')
147 return 0;
148 for (i = 0; i < xMaxOptions; i++)
149 if (strcmp(&inputs[1], xOptions[i]) == 0)
150 break;
151 if (i == xMaxOptions)
152 return 0;
153
154 xOpt.word = 'x';
155 xOpt.dtype = clp_str;
156 xOpt.storage = (pointer_t) & xStorage[i];
157 xOpt.def = i; /* remember which option this was */
158 xOpt.description = optXOpt[i];
159 *clip = &xOpt;
160
161 return 1;
162 }
163 #endif
164
165 /*******************************************************************/
166
167 void
print_usage(clopt)168 print_usage(clopt)
169 clp_opt_t clopt[];
170
171 {
172 clp_opt_t *clip;
173 int i;
174
175 if (!printed_usage) {
176 sprintf(outs, credits_screen1, PMARSVER / 100, (PMARSVER % 100) / 10,
177 PMARSVER % 10, PMARSDATE);
178 errout(outs);
179 errout(credits_screen2);
180 errout(credits_screen3);
181 errout(usage_screen);
182 errout(optionsAre);
183 for (i = 0, clip = clopt; clip->storage != NULL; ++clip) {
184 if (clip->description != NULL) {
185 sprintf(outs, " -%c %s %-30s",
186 clip->word, describe[(int) clip->dtype], clip->description);
187 errout(outs);
188 if (i++ % 2)
189 errout("\n");
190 }
191 }
192 #ifndef MACGRAPHX
193 errout(readOptionsFromFile);
194 #endif
195 #if defined(XWINGRAPHX)
196 for (i = 0; i < xMaxOptions; i++) {
197 sprintf(outs, " -%-8s $ %-24s", xOptions[i], optXOpt[i]);
198 errout(outs);
199 if (i % 2)
200 errout("\n");
201 }
202 #endif
203 printed_usage = TRUE;
204 }
205 }
206
207 /******************************************************
208 * read from the command line, command file, or stdin *
209 ******************************************************/
210
211 int
next_input(filep,inputs)212 next_input(filep, inputs)
213 FILE *filep;
214 char *inputs;
215 {
216 int i;
217 if (filep == NULL) { /* read from command line */
218 if (argc) {
219 strcpy(inputs, *argv);
220 --argc;
221 ++argv;
222 } else
223 *inputs = '\0'; /* read from command file or stdin */
224 } else {
225 *inputs = '\0';
226 /* if (!feof(filep)) */
227 fscanf(filep, "%s", inputs);
228 if (*inputs == '"') { /* quoted string */
229 *inputs = ' ';
230 i = strlen(inputs);
231 if (inputs[i - 1] == '"')
232 inputs[i - 1] = '\0';
233 else
234 fscanf(filep, "%[^\"]%*[\"]", inputs + i);
235 }
236 while (*inputs == ';') {
237 fgets(inputs, 100, filep);
238 *inputs = '\0';
239 fscanf(filep, "%s", inputs);
240 }
241 }
242 if (!strcmp(inputs, "$")) /* end of input marker */
243 return 0;
244 return strlen(inputs);
245 }
246
247 /************************************************************************
248 * Read the options (called recursively) This is the heart of clparse.c *
249 ************************************************************************/
250
251 int
clp_parse(clopt,filep)252 clp_parse(clopt, filep)
253 clp_opt_t clopt[];
254 FILE *filep;
255
256 {
257
258 enum {
259 NONE, OPTION, ARGUMENT, RANGE, TOO_MANY, MEMORY, FILENAME, OLDERROR
260 } code;
261 clp_opt_t *clip;
262 unsigned bool_switch;
263 char inputs[CLP_MAXSTRLEN];
264 FILE *newFile;
265
266 code = NONE; /* no error so far */
267 while (next_input(filep, inputs)) {
268 if ((inputs[0] == '-') && inputs[1]) { /* option ? */
269 int i;
270
271 bool_switch = 1; /* no argument needed for this option */
272 for (i = 1; inputs[i] && (bool_switch); ++i) {
273 for (clip = clopt; /* find which option is this */
274 (clip->storage != NULL) &&
275 (inputs[i] != clip->word);
276 ++clip);
277 #if defined(XWINGRAPHX)
278 if (!xwin_decode(inputs, &clip) && inputs[i] != clip->word) {
279 #else
280 if (inputs[i] != clip->word) { /* option not found */
281 #endif
282 #ifndef MACGRAPHX
283 if (inputs[i] == '@') { /* included command file? */
284 if (inputs[i + 1] != '\0') {
285 code = FILENAME; /* must have a parameter */
286 goto ERROR;
287 } else {
288 bool_switch = 0;
289 if (next_input(filep, inputs)) {
290 if (!strcmp(inputs, "-")) {
291 newFile = stdin;
292 fprintf(stderr, readingStdin);
293 } else {
294 if ((newFile = fopen(inputs, "r")) == NULL) {
295 code = FILENAME; /* command file not found */
296 goto ERROR;
297 }
298 }
299 } else {
300 code = FILENAME;/* no parameter for -@ */
301 goto ERROR;
302 }
303 }
304 if ((clp_parse(clopt, newFile)) != NONE) {
305 code = OLDERROR;
306 if (newFile == stdin)
307 strcpy(inputs, standardInput);
308 goto ERROR; /* error in command file */
309 }
310 } else /* no such option */
311 #endif /* MACGRAPHX */
312 {
313 code = OPTION;
314 goto ERROR;
315 }
316 } else { /* option found */
317 if (clip->dtype == clp_bool)
318 clip->def = !(clip->def);
319 else { /* not a bool switch, value needed */
320 bool_switch = 0;
321 #if defined (XWINGRAPHX)
322 if (clip->word != 'x' && inputs[i + 1] != '\0') {
323 #else
324 if (inputs[i + 1] != '\0') {
325 #endif
326 code = ARGUMENT; /* middle option */
327 goto ERROR; /* but we need an argument */
328 } else {
329 if (!next_input(filep, inputs)) {
330 code = ARGUMENT;/* no argument */
331 goto ERROR;
332 } else if (clip->dtype == clp_str) {
333 if ((*(char **) clip->storage =
334 (char *)
335 malloc((strlen(inputs) + 1) * sizeof(char))) != NULL) {
336 strcpy(*(char **) clip->storage, inputs);
337 } else {
338 code = MEMORY;
339 goto ERROR;
340 }
341 } else {
342 char *idx;
343 clip->def = atol(inputs);
344 for (idx = inputs; *idx && isdigit(*idx); ++idx);
345 if (*idx) {
346 code = ARGUMENT;
347 goto ERROR;
348 }
349 if (clip->def < (clip->min) ||
350 clip->def > (clip->max)) {
351 code = RANGE;
352 goto ERROR;
353 }
354 }
355 }
356 }
357 }
358 }
359 } else {
360 if (warriors < MAXWARRIOR) {
361 int many;
362
363 code = NONE;
364 #ifndef MACGRAPHX
365 many = strlen(inputs) - 1;
366 if (inputs[many] == '-') { /* warrior from stdin */
367 if (!many) {
368 many++;
369 } else { /* number before - ? */
370 inputs[many] = 0; /* kill the - sign */
371 many = atoi(inputs);/* how many warriors from stdin */
372 if (!many) {
373 code = OPTION;
374 goto ERROR;
375 }
376 }
377 *inputs = '\0';
378 } else
379 #endif
380 many = 1;
381 for (; many; many--) {
382 if ((warrior[warriors].fileName =
383 (char *) malloc((strlen(inputs) + 1) * sizeof(char))) != NULL) {
384 strcpy(warrior[warriors++].fileName, inputs);
385 } else {
386 code = MEMORY;
387 goto ERROR;
388 }
389 }
390 } else {
391 code = TOO_MANY;
392 goto ERROR;
393 }
394 }
395 }
396 return (0);
397
398 ERROR:
399
400 if (code != OLDERROR)
401 print_usage(clopt);
402 switch (code) {
403 case NONE:
404 break;
405 case OLDERROR:
406 sprintf(outs, errorIsLocatedIn, inputs);
407 errout(outs);
408 break;
409 case OPTION:
410 sprintf(outs, unknownOption, inputs);
411 errout(outs);
412 break;
413 case ARGUMENT:
414 #if defined(XWINGRAPHX)
415 if (clip->word == 'x')
416 sprintf(outs, badArgumentForXSwitch, xOptions[clip->def]);
417 else
418 #endif
419 sprintf(outs, badArgumentForSwitch, clip->word);
420 errout(outs);
421 break;
422 case RANGE:
423 sprintf(outs, optionMustBeInTheRange, clip->word);
424 errout(outs);
425 sprintf(outs, "%ld - %ld\n", (clip->min), (clip->max));
426 errout(outs);
427 break;
428 case TOO_MANY:
429 sprintf(outs, tooManyParameters, inputs);
430 errout(outs);
431 break;
432 case MEMORY:
433 sprintf(outs, outOfMemory);
434 errout(outs);
435 break;
436 case FILENAME:
437 sprintf(outs, cannotOpenParameterFile);
438 errout(outs);
439 break;
440 }
441 return (CLP_NOGOOD);
442 }
443
444 int
445 #ifdef PARSETEST
main(largc,largv)446 main(largc, largv)
447 #else
448 parse_param(largc, largv)
449 #endif
450
451 int largc;
452 char **largv;
453 {
454
455 int result;
456 clp_opt_t *clip;
457 int i;
458 long dummy;
459
460 /*******************************************************************
461 * command line parameters and options *
462 ********************************************************************/
463
464 #define OPTNUM 21 /* don't forget to increase when adding new
465 * options */
466 static clp_opt_t options[OPTNUM];
467 int optI = 0; /* used by record() macro */
468
469 #ifdef PERMUTATE
470 record('r', clp_int, &rounds, 0, MAXROUND,
471 -1, optRounds);
472 #else
473 record('r', clp_int, &rounds, 0, MAXROUND,
474 DEFAULTROUNDS, optRounds);
475 #endif
476 #ifndef SERVER
477 record('e', clp_bool, &SWITCH_e, 0, 1,
478 0, optEnterDebugger);
479 #else
480 record('e', clp_bool, &SWITCH_e, 0, 1,
481 0, optDisabledInServerVersion);
482 #endif
483 record('s', clp_addr, &coreSize, 1, MAXCORESIZE,
484 DEFAULTCORESIZE, optCoreSize);
485 record('b', clp_bool, &SWITCH_b, 0, 1,
486 0, optBrief);
487 record('c', clp_long, &cycles, 1, MAXCYCLE,
488 DEFAULTCYCLES, optCycles);
489 record('V', clp_bool, &SWITCH_V, 0, 1, 0, optVerboseAssembly);
490 record('p', clp_int, &taskNum, 1, MAXTASKNUM,
491 DEFAULTTASKNUM, optProcesses);
492 record('k', clp_bool, &SWITCH_k, 0, 1,
493 0, optKotH);
494 record('l', clp_addr, &instrLim, 1, MAXINSTR,
495 DEFAULTINSTRLIM, optLength);
496 record('8', clp_bool, &SWITCH_8, 0, 1,
497 0, opt88);
498 record('d', clp_addr, &separation, 1, MAXSEPARATION,
499 0, optDistance);
500 record('f', clp_bool, &SWITCH_f, 0, 1,
501 0, optFixedSeries);
502 record('F', clp_addr, &SWITCH_F, 0, MAXCORESIZE,
503 0, optFixedPosition);
504 record('o', clp_bool, &SWITCH_o, 0, 1, 0,
505 optSort);
506 #if defined(PSPACE)
507 record('S', clp_addr, &pSpaceSize, 1,
508 MAXCORESIZE, 0, optPSpaceSize);
509 #endif
510 #ifdef PERMUTATE
511 record('P', clp_bool, &SWITCH_P, 0, 1,
512 0, optPermutate);
513 #endif
514 record('=', clp_str, &SWITCH_eq, 0, 0, 0, optScoreFormula);
515 record('Q', clp_int, &SWITCH_Q, -1, INT_MAX, -1, NULL);
516 #if defined(DOSTXTGRAPHX) || defined(DOSGRXGRAPHX) || defined(LINUXGRAPHX) \
517 || defined(XWINGRAPHX)
518 #if defined(XWINGRAPHX)
519 #define V_MAX 2994
520 #else
521 #define V_MAX 994
522 #endif
523 record('v', clp_int, &SWITCH_v, 0, V_MAX,
524 103, optView);
525 #undef V_MAX
526 #endif
527 #if defined(VMS)
528 record('D', clp_bool, &SWITCH_D, 0, 1, 0,
529 optDIAOutput);
530 #endif
531 record((char) 0, (clp_dtype_t) 0, NULL, 0, 0,
532 0, NULL);
533 /*******************************************************************/
534 /* initializing default values */
535 for (i = 0; i < MAXWARRIOR; i++) {
536 warrior[i].fileName = NULL;
537 warrior[i].fileName = NULL;
538 }
539
540 /*******************************************************************/
541 argv = largv;
542 argc = largc;
543 ++argv;
544 --argc; /* skip program name */
545 warriors = 0;
546 printed_usage = FALSE;
547 result = clp_parse(options, NULL);
548 if (!result) { /* so far so good */
549 {
550 for (clip = options; clip->storage != NULL; ++clip) {
551 if (clip->dtype == clp_long)
552 *(CLP_LONG *) clip->storage = clip->def;
553 else if (clip->dtype == clp_int)
554 *(CLP_INT *) clip->storage = (CLP_INT) clip->def;
555 else if (clip->dtype == clp_addr)
556 *(CLP_ADDR *) clip->storage = (CLP_ADDR) clip->def;
557 else if (clip->dtype == clp_bool)
558 *(CLP_INT *) clip->storage = (CLP_INT) clip->def;
559 }
560
561 if (SWITCH_f && SWITCH_F) {
562 print_usage(options);
563 errout(fFExclusive);
564 result = CLP_NOGOOD;
565 }
566 if (separation == 0)
567 separation = instrLim;
568 else if (separation < instrLim) {
569 print_usage(options);
570 errout(dLessThanl);
571 result = CLP_NOGOOD;
572 }
573 if (coreSize < (warriors * separation)) {
574 print_usage(options);
575 errout(coreSizeTooSmall);
576 result = CLP_NOGOOD;
577 }
578 if ((SWITCH_F) && (separation > SWITCH_F)) {
579 print_usage(options);
580 errout(FLessThand);
581 result = CLP_NOGOOD;
582 }
583 set_reg('W', (long) warriors);
584 for (i = 1; i <= warriors; ++i) {
585 set_reg('S', (long) i);
586 if (eval_expr(SWITCH_eq, &dummy) < OK_EXPR) {
587 print_usage(options);
588 errout(badScoreFormula);
589 result = CLP_NOGOOD;
590 break;
591 }
592 }
593 #ifdef PSPACE
594 if (pSpaceSize == 0) /* make default, at least 1/16th of coresize */
595 for (i = 16; i > 0; --i)
596 if (!(coreSize % i)) {
597 pSpaceSize = coreSize / i;
598 break;
599 }
600 if (pSpaceSize > coreSize) {
601 print_usage(options);
602 errout(pSpaceTooBig);
603 result = CLP_NOGOOD;
604 }
605 #endif
606 #ifdef PERMUTATE
607 if (SWITCH_P) {
608 if (warriors != 2) {
609 print_usage(options);
610 errout(permutateMultiWarrior);
611 result = CLP_NOGOOD;
612 } else if (rounds < 0) /* all possible combinations */
613 rounds = 2*coreSize-4*separation+2;
614 } else if (rounds < 0 )
615 rounds = DEFAULTROUNDS;
616 #endif
617 /* further checks of the values */
618
619 #ifndef OS2PMGRAPHX /* jk - we can load files after the fact... */
620 if (warrior[0].fileName == NULL) {
621 print_usage(options);
622 errout(noWarriorFile);
623 result = CLP_NOGOOD;
624 }
625 #endif
626 }
627 }
628 return result;
629 }
630
631
632
633