1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Bull Inc., 1987                *
  4    *                                                         *
  5    * Copyright, (C) Honeywell Information Systems Inc., 1986 *
  6    *                                                         *
  7    *********************************************************** */
  8 
  9 /* HISTORY COMMENTS:
 10   1) change(86-01-01,Flegel), approve(87-07-13,MCR7580),
 11      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 12      Created.
 13   2) change(86-01-20,ASmith), approve(87-07-13,MCR7580),
 14      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 15      Documentation and added call to getc_buff and allocated space for unions.
 16   3) change(86-05-07,Lee), approve(87-07-13,MCR7580), audit(87-07-13,Leskiw),
 17      install(87-08-07,MR12.1-1072):
 18      Added call to init_cat, allocated cat tables.
 19   4) change(86-08-25,Flegel), approve(87-07-13,MCR7580),
 20      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 21      Modified documentation.
 22   5) change(86-08-27,Flegel), approve(87-07-13,MCR7580),
 23      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 24      Installed /M option.
 25   6) change(86-09-17,Flegel), approve(87-07-13,MCR7580),
 26      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 27      Extracted option parsing into separate routine and installed start-up
 28      file support (/F).
 29   7) change(87-03-15,Flegel), approve(87-07-13,MCR7580),
 30      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 31      Re-wrote argument processing, it was wrong before.
 32   8) change(87-03-24,Flegel), approve(87-07-13,MCR7580),
 33      audit(87-07-13,Leskiw), install(87-08-07,MR12.1-1072):
 34      Added /E and /N options to allow access to escaping special characters
 35      and specifying that the connection will be via network.
 36   9) change(88-01-26,Flegel), approve(88-02-29,MCR7853),
 37      audit(88-03-10,Nakaska), install(88-03-15,MR12.2-1036):
 38      Added /H option to hold DTR high when connecting.
 39  10) change(88-06-17,Lee), approve(88-07-18,MCR7936), audit(88-08-10,Flegel),
 40      install(88-08-23,MR12.2-1091):
 41      Added support for Mark and Space parity.
 42                                                    END HISTORY COMMENTS */
 43 
 44 /* :  PROCEDURE FUNCTION (MOWSE):
 45 
 46 MOWSE command which loads MOWSE into PC memory.
 47 */
 48 
 49 /* : NOTES:
 50 
 51 The following is a list of command line options:
 52 
 53          /B - baud
 54          /C - communications port
 55          /D - data bits
 56          /E - escape character
 57          /F - start_up file
 58          /G - debug packets
 59          /H - hold DTR
 60          /I - user interrupt
 61          /L - autoload capability
 62          /M - turn on communications' error messages
 63          /N - Network connection
 64          /P - parity
 65          /S - stop bits
 66 */
 67 
 68 #include <dos.h>
 69 #include <stdio.h>
 70 #include <fcntl.h>
 71 #include <ws.h>
 72 #include <mowsdefs.h>
 73 #include <alloc.h>
 74 #include <cat.h>
 75 #include <ws_fgb.h>
 76 #include <ws_auto.h>
 77 #include <emulator.h>
 78 
 79 #define BADARG       -1                /* Invalid parameter */
 80 #define BADOPTION    -2                /* Invalid option */
 81 #define OVERLOAD     -3                /* Too many autoload capabilities */
 82 #define EXPECTING    -4                /* Argument expected */
 83 #define BADCONTROL   -5                /* Option specifier ('/') expected */
 84 
 85 #define OPTION_BUILT         001        /* Completed option */
 86 #define PARAM_BUILT          002        /* Completed parameter */
 87 #define OPTION_PENDING       004        /* Expecting option char */
 88 #define PARAM_PENDING        010        /* Expecting one word of parameter */
 89 #define READ_FILE            020        /* Start_up file specified */
 90 
 91 #define DEFAULT_BAUD         B9600
 92 #define DEFAULT_PARITY       EVEN_PAR
 93 #define DEFAULT_STOP         STOP1
 94 #define DEFAULT_DATAB        DATA7
 95 #define DEFAULT_SOFTNO       97
 96 #define DEFAULT_COM_PORT     0x3f8
 97 #define DEFAULT_COM_NO       0
 98 #define DEFAULT_MASK8259     0xef
 99 #define DEFAULT_HARDINTRPT   0xc
100 #define DEFAULT_ERROR_MODE   0
101 
102 #define WS_MEMORY_SIZE   2048 /* Size of MOWSE memory (4096 until MOWSE got too big) */
103 
104 extern AUTO load_list[];      /* Autoload list of capabilities */
105 extern int load_list_pending; /* Autoload pending */
106 extern int _TOP;              /* TOP of stack as defined by C compiler */
107 extern int dbgpkts;           /* =1, to show level 2 packets */
108 extern int dbgrejs;           /* =1, to show rejected level 2 packets */
109 extern int dbgxchr;           /* =1, tp show extraneous received characters */
110 extern char s_escreq[256];    /* escape character flags */
111 extern char s_EOP;            /* Sender EOP character */
112 extern char r_EOP;            /* Receiver EOP character */
113 int        datab;             /* Data bit parameter */
114 int        _stack = 12288;    /* MOWSE needs a large runtime stack */
115 int        SOFTNO;            /* Software interrupt number for sub. library */
116 int        COM_PORT;          /* hardware address of comm port */
117 int        COM_NO;            /* number of comm port (COM1 or COM2)   */
118 char       MASK8259;          /* mask for setting enabling hardware interrupts */
119 int        HARDINTRPT;        /* hardware interrupt number */
120 int        packetize_flag;    /* Current packet mode */
121 
122 local_cat       l_CAT [ NUMBER_OF_CAT_ENTRIES ]; /* Local CAT */
123 remote_cat      r_CAT [ NUMBER_OF_CAT_ENTRIES ]; /* Remote CAT */
124 int             NEW_INSTANCE_;
125 
126 char            fg_memory[WS_MEMORY_SIZE];  /* Foreground linked list buffer */
127 struct allocstr fgastr,
128                 *fgaptr;
129 
130 char            bg_memory[WS_MEMORY_SIZE];  /* Background linked list buffer */
131 struct allocstr bgastr,
132                 *bgaptr;
133 
134 struct allocstr lcastr,
135                 *lcaptr;
136 
137 struct fgbstr *lcbfptr;                /* first entry on local_cap queue */
138 struct fgbstr *lcblptr;                /* last message on local_cap queue */
139 struct fgbstr *fgbfptr;                /* first entry on foreground queue */
140 struct fgbstr *fgblptr;                /* last message on foreground queue */
141 struct fgbstr *bgbfptr;                /* first entry on background queue */
142 struct fgbstr *bgblptr;                /* last message on background queue */
143 struct fgbstr *sgbfptr;                /* first entry on status queue */
144 struct fgbstr *sgblptr;                /* last message on status queue */
145 
146 int  bgcount;                          /* count of number of background messages */
147 int  error_mode;                       /* whether or not to print modem error messages */
148 char lc_memory[WS_MEMORY_SIZE];        /* memory for local cap  linked list buffer */
149 
150 int  startup_flags = 0;                /* Flags indicating which options have been set */
151 
152 main(argc,argv)
153 int argc;
154 char *argv[];
155 {
156 int          i;
157 int          baud;                     /* Communication line configuration */
158 int          parity;
159 int          stop;
160 int          comm_parameter;
161 int          flags;                   /* Flags for control information */
162 int          arg_count;               /* Number of parameters used in an option */
163 char         option;                  /* Command line option */
164 char         parameter[32];           /* Command line parameter */
165 char         start_file[32];
166 unsigned     highmem;                 /* Terminate and stay resident parameters */
167 union REGS   in_reg;                  /*    Register values of MOWSE */
168 struct SREGS segregs;                 /*    Segment register values of MOWSE */
169 
170 /* : Initialzation */
171 
172    printf ("MOWSE version %d.%d ...", VERSION, SUBVERSION);
173 
174    fgaptr             = &fgastr;
175    fgastr.memory_used = 0;
176    fgastr.memory      = &fg_memory[0];
177    fgastr.m_allocp    = NULL;
178    fgastr.memory_size = WS_MEMORY_SIZE;
179    fgbfptr            = NULL;
180    fgblptr            = NULL;
181    bgaptr             = &bgastr;
182    bgastr.memory_used = 0;
183    bgastr.memory      = &bg_memory[0];
184    bgastr.m_allocp    = NULL;
185    bgastr.memory_size = WS_MEMORY_SIZE;
186    bgbfptr            = NULL;
187    bgblptr            = NULL;
188    bgcount            = 0;
189    lcaptr             = &lcastr;
190    lcastr.memory_used = 0;
191    lcastr.memory      = &lc_memory[0];
192    lcastr.m_allocp    = NULL;
193    lcastr.memory_size = WS_MEMORY_SIZE;
194    lcbfptr            = NULL;
195    lcblptr            = NULL;
196    sgbfptr            = NULL;
197    sgblptr            = NULL;
198 
199 /* : set default com port parameters. */
200 
201    baud               = DEFAULT_BAUD;
202    parity             = DEFAULT_PARITY;
203    stop               = DEFAULT_STOP;
204    datab              = DEFAULT_DATAB;
205    comm_parameter     = DEF_COMM;
206 
207    SOFTNO             = DEFAULT_SOFTNO;
208    COM_PORT           = DEFAULT_COM_PORT;  /* hardware address of COM1 port */
209    COM_NO             = DEFAULT_COM_NO;    /* set com1 port */
210    MASK8259           = DEFAULT_MASK8259;  /* reset: IRQ4 */
211    HARDINTRPT         = DEFAULT_HARDINTRPT;/* hardware (communications) interrupt  */
212    error_mode         = DEFAULT_ERROR_MODE;
213 
214    flags              = 0;
215    startup_flags      = 0;
216    start_file[0]      = 0;
217 
218    load_list_pending  = 0;
219    for (i = 0; i < AUTO_LIMIT; load_list[i++].flags = 0);
220 
221 /* : Parse command line parameters */
222 
223    for (i = 1; i < argc;)
224    {  if (argv[i][0] == '/')
225       {  option = argv[i][1];
226          if (argv[i][2])
227             strcpy (parameter, &(argv[i][2]));
228          else
229             strcpy (parameter, argv[i+1]);
230 
231          arg_count = parse_options (option, parameter, &stop, &parity, &baud,
232             &datab, start_file);
233          if (arg_count < 0)
234             exit (0);
235 
236          if (argv[i][2])
237             i += 1;
238          else
239             i += (1 + arg_count);
240       }
241       else
242       {  parse_error (BADCONTROL, argv[i][0], NULL);
243          exit (0);
244       }
245    }
246 
247 /* : If start_up file specified, parse through it */
248 
249    if (start_file[0])
250       if (start_up_parser (start_file, &stop, &parity, &baud, &datab) < 0)
251          exit (0);
252 
253 /* : Initialize_mowse if MOWSE not already active
254      - set communications port parameter
255      - initialize the local and remote cat tables
256      - start up MOWSE dumb terminal emulator
257      - setup the memory location to be used to delimit code which
258        is to remain resident
259      - terminate and stay resident */
260 
261    /* set bits 8 to 10 for handling Mark and Space parity */
262    if (parity == MARK_PAR || parity == SPAC_PAR) {
263        comm_parameter = ((baud<<5)|(NO_PAR<<3)|(stop<<2)|(datab));
264        comm_parameter |= parity << 8;
265    }
266    else
267        comm_parameter = ((baud<<5)|(parity<<3)|(stop<<2)|(datab));
268 
269    if (initialize_mowse(comm_parameter) == 1)
270    {  init_cat();
271       printf ("\n");                                  /* We're done initializing */
272 
273 #if EM_DEBUG
274       em();
275 #endif
276       printf ("\nResident portion of MOWSE installed on COM%d:\n", COM_NO + 1);
277 
278       segread(&segregs);
279       highmem = _TOP + 16;
280 
281       in_reg.x.dx = (int) (highmem >> 4)+(segregs.ds-segregs.cs);
282       in_reg.h.ah = 0x31;
283       int86(33,&in_reg,0);
284    }
285    else
286       printf (" already resident.\n");
287 }
288 
289 /*^L*/
290 
291 /* : PROCEDURE FUNCTION (start_up_parser):
292 
293 Parse through the start-up file specified.  The start-up file is interpretted
294 as follows:
295 
296         /X  parameter
297 
298 where X is one of
299 
300         B,C,D,F,G,I,L,M,S
301 
302 as defined for the parameter specifications for the command MOWSE.
303 */
304 
305 /* : RETURNS
306 
307       0 - all OK
308     < 0 - an error occurred
309 */
310 
311 /* : NOTES
312 
313 Capabilites that are to be autoloaded areshuffled off until MOWSE is active on
314 both Multics and the PC.
315 
316 Command line options have precedence over start-up file specifications.  Thus
317 if for example /D is specified in the command line, then it will override any
318 mention of the option in the start up file.
319 
320 If MOWSE is exitted normally BEFORE MOWSE is started up on Multics, all autoload
321 specifications will be lost.
322 
323 /F options specified in the start_up file are treated as errors as recursive
324 start_up files are not acceptable.
325 */
326 
327 start_up_parser (p_file, p_stop, p_parity, p_baud, p_datab)
328 
329 char p_file[];        /* NULL terminated string specifying startup file name */
330 int  *p_stop;         /* Stop bits */
331 int  *p_parity;       /* Parity */
332 int  *p_baud;         /* Baud rate */
333 int  *p_datab;        /* Data bits */
334 {
335 int  fd;              /* File Descriptor to start_up file */
336 int  i;
337 int  param_idx;       /* Position in parameter construction */
338 char buffer[257];     /* Input line from file */
339 char parameter[33];   /* Parmater being built */
340 int  n_chars;         /* Chars read from input file */
341 int  code;            /* Error code */
342 int  flags;           /* Current flag settings */
343 char option;          /* Option specified */
344 char junk[32];        /* Useless space */
345 
346 /* : Open the file to read */
347    if ((fd = open (p_file, O_RDONLY)) == -1)
348    {  printf (" Error opening %s.\n", p_file);
349       return (-1);
350    }
351 
352 /* : While not EOF
353      - For each character extracted from the file
354      -- If char = '/', done getting last parameter, process option, clear flags
355      -- Else if char non-printable, done collection of parameter, process option
356      -- Else (printable character), build option or parameter */
357 
358    flags = 0;
359    while ((n_chars = read (fd, buffer, 256)) > 0)
360    {  for (i = 0; i < n_chars; i++)
361       {  if (buffer[i] == '/')
362          {  if (flags & PARAM_PENDING)
363             {  if (option == 'F' || option == 'f')
364                {  printf (" Cannot load start_up files recursively.\n");
365                   close (fd);
366                   return (-1);
367                }
368                parameter[param_idx++] = 0;
369                if ((code = parse_options (option, parameter, p_stop, p_parity, p_baud, p_datab, junk)) < 0)
370                {  close (fd);
371                   return (code);
372                }
373             }
374             flags = OPTION_PENDING;
375             option = 0;
376             param_idx = 0;
377             parameter[0] = 0;
378          }
379 
380          else if (buffer[i] <= '\040' || buffer[i] >= '\177')
381          {  if (flags & PARAM_PENDING && param_idx)
382             {  flags = (flags ^ PARAM_PENDING) | PARAM_BUILT;
383                if (option == 'F' || option == 'f')
384                {  printf (" Cannot load start_up files recursively.\n");
385                   close (fd);
386                   return (-1);
387                }
388                parameter[param_idx++] = 0;
389                if ((code = parse_options (option, parameter, p_stop, p_parity, p_baud, p_datab, junk)) < 0)
390                {  close (fd);
391                   return (code);
392                }
393             }
394          }
395 
396          else
397          {  if (flags & OPTION_PENDING)
398             {  option = buffer[i];
399                flags = (flags ^ OPTION_PENDING) | OPTION_BUILT | PARAM_PENDING;
400             }
401             else if (flags & PARAM_PENDING)
402                parameter[param_idx++] = buffer[i];
403          }
404       }
405    }
406 
407    close (fd);
408    return (0);
409 }
410 
411 /*^L*/
412 
413 /* : PROCEDURE FUNCTION (parse_options):
414 
415 Parse the option and its parameter and handle accordingly.
416 */
417 
418 /* : RETURNS
419 
420      0         - OK
421      BADARG    - Invalid parameter
422      BADOPTION - Invalid option
423      OVERLOAD  - Too many autoload capabilities
424      EXPECTING - Argument expected
425 */
426 
427 /* : NOTES
428 
429 If an error occurs, the error message is printed from parse_options and the
430 error code (above) is returned.
431 */
432 
433 parse_options (p_option, p_param, p_stop, p_parity, p_baud, p_datab, p_start)
434 
435 char p_option;           /* Option */
436 char p_param[];          /* Parameter to option (may be 0 length) */
437 int  *p_stop;            /* Stop bits */
438 int  *p_parity;          /* Parity */
439 int  *p_baud;            /* Baud rate */
440 int  *p_datab;           /* Data bits */
441 char p_start[];          /* Start_up file name */
442 {
443 int  j;                  /* Temp */
444 int  i;
445 int  code;               /* Error code */
446 int  arg_count;          /* Number of arguments extracted */
447 int  index;              /* Escape character value */
448 int  convert_code;       /* Escape char conversion code */
449 
450    arg_count = 0;
451    code = 0;
452 
453    switch (p_option)
454    {  case 'B':                        /* BAUD */
455       case 'b':
456 
457          arg_count = 1;
458          if (startup_flags & OPTION_B)
459             break;
460          else if (!(p_param[0]) || (p_param[0] == '/'))
461             code = EXPECTING;
462          else switch (atoi(p_param))
463          {  case 110:  *p_baud = B110;  break;
464             case 150:  *p_baud = B150;  break;
465             case 300:  *p_baud = B300;  break;
466             case 600:  *p_baud = B600;  break;
467             case 1200: *p_baud = B1200; break;
468             case 2400: *p_baud = B2400; break;
469             case 4800: *p_baud = B4800; break;
470             case 9600: *p_baud = B9600; break;
471             default:
472                code = BADARG;
473          }
474          startup_flags |= OPTION_B;
475          break;
476 
477       case 'C':                        /* COM PORT */
478       case 'c':
479 
480          if (startup_flags & OPTION_C)
481             break;
482 
483          arg_count = 1;
484          if (!(p_param[0]) || (p_param[0] == '/'))
485             code = EXPECTING;
486          else switch (atoi(p_param))
487          {  case 1:
488 
489                COM_PORT = DEFAULT_COM_PORT;    /* hardware address of COM1 port */
490                COM_NO = DEFAULT_COM_NO;        /* set com1 port */
491                MASK8259 = DEFAULT_MASK8259;    /* reset: IRQ4 */
492                HARDINTRPT= DEFAULT_HARDINTRPT; /* hardware interrupt  */
493                break;
494 
495             case 2:
496 
497                COM_PORT = 0x2f8;       /* hardware address of COM2 port */
498                COM_NO = 1;             /* set com2 port */
499                MASK8259 = (char) 0xf7; /* reset: IRQ3 */
500                HARDINTRPT= 0xb;        /* hardware interrupt  */
501                break;
502 
503             default:
504 
505                code =  BADARG;
506          }
507          startup_flags |= OPTION_C;
508          break;
509 
510       case 'D':                        /* DATA BITS */
511       case 'd':
512 
513          if (startup_flags & OPTION_D)
514             break;
515 
516          arg_count = 1;
517          if (!(p_param[0]) || (p_param[0] == '/'))
518             code = EXPECTING;
519          else switch (atoi(p_param))
520          {  case 7:  *p_datab = DATA7; break;
521             case 8:  *p_datab = DATA8; break;
522             default: code = BADARG;
523          }
524          startup_flags |= OPTION_D;
525          break;
526 
527       case 'E':                        /* Escape character */
528       case 'e':
529 
530          arg_count = 1;
531          if (!(p_param[0]) || (p_param[0] == '/'))
532             code = EXPECTING;
533          else
534          {  convert_code = sscanf (p_param, "%o", &index);
535             if (convert_code != 1)
536                code = BADARG;
537             else if ((index < 0) || (index > 255))
538                code = BADARG;
539             else
540                s_escreq[index] = 1;
541          }
542 
543          break;
544 
545       case 'F':                        /* START_UP FILE */
546       case 'f':
547 
548          if (!(p_param[0]) || (p_param[0] == '/'))
549             strcpy (p_start, "MOWSE.INI");
550          else
551          {  stccpy (p_start, p_param, 31);
552             p_start[31] = 0;
553             arg_count = 1;
554          }
555          break;
556 
557       case 'G':                        /* DEBUG PACKETS */
558       case 'g':
559 
560          arg_count = 1;
561          if (!(p_param[0]) || (p_param[0] == '/'))
562             code = EXPECTING;
563          else switch (p_param[0])
564          {  case 'P':                  /* Show all packets */
565             case 'p':
566 
567                if (startup_flags & OPTION_GP)
568                   break;
569                startup_flags |= OPTION_GP;
570                dbgpkts = 1;
571                break;
572 
573             case 'R':                  /* Show rejected packets */
574             case 'r':
575 
576                if (startup_flags & OPTION_GR)
577                   break;
578                startup_flags |= OPTION_GR;
579                dbgpkts = 1;
580                break;
581 
582             case 'X':                  /* Show extra characters */
583             case 'x':
584 
585                if (startup_flags & OPTION_GX)
586                   break;
587                startup_flags |= OPTION_GX;
588                dbgpkts = 1;
589                break;
590 
591             default:
592                code = BADARG;
593          }
594          break;
595 
596       case 'H':                        /* HOLD DTR */
597       case 'h':
598          startup_flags |= OPTION_H;
599          break;
600 
601       case 'I':                        /* USER MOWSE INTERRUPT */
602       case 'i':
603 
604          if (startup_flags & OPTION_I)
605             break;
606 
607          arg_count = 1;
608          if (!(p_param[0]) || (p_param[0] == '/'))
609             code = EXPECTING;
610          else
611          {  j = atoi(p_param);
612             if ((j > 10) && (j < 256))
613                SOFTNO = j;
614             else
615                code = BADARG;
616          }
617          startup_flags |= OPTION_I;
618          break;
619 
620       case 'L':                        /* AUTOLOAD CAPABILITY */
621       case 'l':
622 
623          arg_count = 1;
624          if (!(p_param[0]) || (p_param[0] == '/'))
625             code = EXPECTING;
626 
627          if (!code)
628          {  for (i = 0; (i < AUTO_LIMIT) && (load_list[i].flags & AUTO_ON); i++);
629             if (i == AUTO_LIMIT)
630                code = OVERLOAD;
631          }
632 
633          if (!code)
634          {  strncpy (load_list[i].name, p_param, AUTO_LENGTH - 1);
635             load_list_pending = AUTO_PENDING;
636             load_list[i].name[AUTO_LENGTH] = 0;
637             load_list[i].flags = AUTO_ON;
638          }
639          break;
640 
641       case 'M':                        /* MODEM ERROR MESSAGES */
642       case 'm':
643 
644          error_mode = 1;
645          break;
646 
647       case 'N':                        /* Network Connection */
648       case 'n':
649 
650          arg_count = 0;
651          s_EOP = CR;
652          r_EOP = CR;
653          s_escreq[CR] = 1;
654          break;
655 
656       case 'P':                        /* PARITY */
657       case 'p':
658 
659          if (startup_flags & OPTION_P)
660             break;
661 
662          arg_count = 1;
663          if (!(p_param[0]) || (p_param[0] == '/'))
664             code = EXPECTING;
665          else switch (p_param[0])
666          {  case 'E':
667             case 'e':
668 
669                *p_parity = EVEN_PAR;                /* even parity */
670                break;
671 
672             case 'O':
673             case 'o':
674 
675                *p_parity = ODD_PAR;                 /* odd parity */
676                break;
677 
678             case 'M':
679             case 'm':
680 
681                *p_parity = MARK_PAR;                /* mark parity */
682                break;
683 
684             case 'S':
685             case 's':
686 
687                *p_parity = SPAC_PAR;                /* space parity */
688                break;
689 
690             case 'N':
691             case 'n':
692 
693                *p_parity = NO_PAR;                  /* no parity */
694                *p_datab = DATA8;
695                break;
696 
697             default:
698                code = BADARG;
699          }
700 
701          startup_flags |= OPTION_P;
702          break;
703 
704       case 'S':                        /* STOP BITS */
705       case 's':
706 
707          if (startup_flags & OPTION_S)
708             break;
709 
710          arg_count = 1;
711          if (!(p_param[0]) || (p_param[0] == '/'))
712             code = EXPECTING;
713          else switch (atoi(p_param))
714          {  case 1:  *p_stop = STOP1; break;
715             case 2:  *p_stop = STOP2; break;
716             default: code = BADARG;
717          }
718          startup_flags |= OPTION_S;
719          break;
720 
721       default:
722 
723          code =  BADOPTION;
724    }
725 
726 /* : If there was an error code, then it will cause an exit so return it */
727 
728    if (code)
729    {  parse_error (code, p_option, p_param);
730       return (code);
731    }
732 
733 /* : Else it went OK and return the number of parameters used */
734 
735    return (arg_count);
736 
737 }
738 
739 /*^L*/
740 
741 /* : PROCEDURE FUNCTION (parse_error):
742 
743 Display an appropriate error message for the code.
744 */
745 
746 parse_error (p_code, p_option, p_param)
747 
748 int  p_code;
749 char p_option;
750 char p_param[];
751 {
752 
753    if (p_code == BADARG)
754       printf (" Invalid parameter %s.\n", p_param);
755    else if (p_code == BADOPTION)
756       printf (" Invalid option /%c.\n", p_option);
757    else if (p_code == OVERLOAD)
758       printf (" Too many capabilities to autoload.\n");
759    else if (p_code == EXPECTING)
760       printf (" Argument expected.\n");
761    else if (p_code == BADCONTROL)
762       printf (" Invalid option delimiter: '%c'.\n", p_option);
763 }