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