Date: Tue, 20 Jan 87 11:50:04 est
From: David Krowitz <mit-erl!mit-kermit!ernie!krowitz@EDDIE.MIT.EDU>

Subject: New version of BATCH program
Status: RO

I just found out that I left out one of the files in
my previous distribution of the BATCH program. Here is
a corrected version of the distribution. Run it through
/bin/sh to unpack it.

-- David Krowitz
-----------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	batch.dir
# This archive created: Tue Jan 20 11:47:51 1987
export PATH; PATH=/bin:$PATH
if test ! -d 'batch.dir'
then
	mkdir 'batch.dir'
fi
cd 'batch.dir'
if test -f 'batch'
then
	echo shar: will not over-write existing file "'batch'"
else
cat << \SHAR_EOF > 'batch'
/users/userlib/com/parse_batch ^1 ^2 ^3 ^4 ^5 ^6 ^7 ^8 ^9 ^10 ^11 ^12 ^13 ^14 ^15 | /com/sh
SHAR_EOF
chmod +x 'batch'
fi # end of overwriting check
if test -f 'parse_batch.pas'
then
	echo shar: will not over-write existing file "'parse_batch.pas'"
else
cat << \SHAR_EOF > 'parse_batch.pas'
program parse_batch(input, output);

{ This program parses batch input and outputs a command to be passed
  to the command interpreter.  The idea is to change standard Apollo
  input format into the strange format required for creating remote
  processes.  The real advantage is when names are defaulted.

  The following major change was introduced with version 1.0:  Make
  batch take advantage of the sh_log program, which uses a log file
  to keep track of BOTH error and standard input.

    batch -pn name -n node_id -log logfilename shell_command  shell_parameters
                                        
  is converted to

    crp '/com/sh_log -c @'shell_command  shell_params@' -l logfilename' -on node_id -n name -cps -me

  with appropriate defaults 

  IMPLEMENTATION NOTES:

   This program depends on there being a "sh_log" program available.  Currently this needs to be in
 /com/sh_log.  This can be changed by changing the line in the start_output procedure which refers to
 /com/sh_log to be anywhere the user desires.

  NOTES, PROBLEMS, RESTRICTIONS, ETC:

  See the output_help procedure for these.

  Algorithm summary:
   This is mostly a bookkeeping problem.  The arguments to batch are parsed off and written in the
   other syntax for input to sh_log.  Note that any parameter to batch which is NOT a switch is
   assumed to be the shell command (or script) to execute, along with any of its parameters.
   The command itself (shell_command above) is parsed to obtain the leaf name; this leaf name
   is used to derive the default logfile and process names.

  }

  const max_arguments = 30;  {maximum # of arguments on command line}


        program_version = 1.35;
               {update history:   version 1.1  10/14/85  slp  change sh_log to `node_data/sh_log
                                  version 1.2  10/29/85  slp  for SR9 -- use CRP -ME to transfer SID
                                  version 1.3   2/12/86  slp  change help file to reflect version 1.2 change; also allow /dev/null for logfile
                                  version 1.35  3/21/86  slp  for ADUS -- use /com/sh_log instead of `node_data/com/sh_log}


  %include '/sys/ins/base.ins.pas';
  %include '/sys/ins/name.ins.pas';
  %include '/sys/ins/pgm.ins.pas';
  %include '/sys/ins/pm.ins.pas';
  %include '/sys/ins/streams.ins.pas';
  %include '/sys/ins/vfmt.ins.pas';

  type pathtype = record
                    name: name_$pname_t;
                    length: integer
                  end;

  var process_name,
      logfile_name,
      full_log,
      command,
      full_command,
      username,
      wd,
      node_id:  pathtype;
      name_specified,
      node_specified,
      logfile_specified,
      command_specified,
      silent_specified: boolean;
      misc_status: status_$t;
      i: integer;
      devnull: array[1..*] of char := '/dev/null';   {special name for logfile directed to the null device}
      devnull_size: integer := sizeof(devnull);

  procedure init_globals;

    begin {init_globals}
      node_id.length := 1;
      node_id.name[1] := '/';
      name_specified := false;
      logfile_specified := false;
      command_specified := false;
      node_specified := false;
      silent_specified := false;
    end; {init_globals}

  function exists(var f: pathtype): boolean;
    {This function returns true if the specified file exists}

    var 
       file_attributes:  stream_$ir_rec_t;  
       stream_mask: stream_$inquire_mask_t; {which attributes to get}
       stream_inq_type:  stream_$ir_opt; {how to access file (by name)}
       stream_error_mask: stream_$inquire_mask_t; {status returned}
       i: integer;

    begin {exists}
      stream_mask:= []; {Don't really need any information}
      stream_inq_type := stream_$name_unconditional;
      for i := 1 to f.length do begin
        file_attributes.obj_name[i] := f.name[i];
      end;
      file_attributes.obj_namlen := f.length;
      file_attributes.pre_exist := false;
      stream_$inquire( stream_mask, stream_inq_type, file_attributes, 
                       stream_error_mask, misc_status);
      exists := (misc_status.code <> stream_$name_not_found);
    end;  {exists}

  function is_null(var f: pathtype): boolean;
    {This function returns true if the specified file is /dev/null}

    var i: integer;
        null: boolean;  {local variable for value holder}

    begin {is_null}
      if f.length <> devnull_size then
        is_null := false
      else begin
        null := true;
        i := 1;
        repeat
          if f.name[i] <> devnull[i] then null := false;
          i := i + 1;
        until (not null) or (i > devnull_size);
        is_null := null;
      end;
    end; {is_null}

  procedure start_output;

    begin
      write('crp ''/com/sh_log -v -c @''wd '); {Note:  this can be customized to include a startup script}
      for i := 1 to wd.length do write(wd.name[i]);
      write(';');
    end;

  procedure output_help;

    begin {output_help}
      vfmt_$ws2(stream_$errout,'batch revision %4.2F, 85/5/xx by SLP at Mentor APD%.',program_version,0);
      vfmt_$ws2(stream_$errout,'BATCH  --  submit a command as a background (CPS) process%.',i,i);
      vfmt_$ws2(stream_$errout,'usage:  BATCH  pathname  [-N nodeid] [-PN process_name]%.',i,i);
      vfmt_$ws2(stream_$errout,'                         [-L logfile] [-Silent]%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'FORMAT%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  BATCH  pathname %.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  BATCH creates a background process on the given node and has the%.',i,i);
      vfmt_$ws2(stream_$errout,'  process execute the given command.  The process executes with the same%.',i,i);
      vfmt_$ws2(stream_$errout,'  id as the calling process, in the same working directory as the process.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'ARGUMENTS%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  pathname      The shell command to be executed.  This may be any%.',i,i);
      vfmt_$ws2(stream_$errout,'                command recognized by the command interpreter; thus%.',i,i);
      vfmt_$ws2(stream_$errout,'                it may be a shell script or an object file.%.',i,i);
      vfmt_$ws2(stream_$errout,'                If the command has arguments, enclose the command%.',i,i);
      vfmt_$ws2(stream_$errout,'                AND any arguments in quotes.  For example:%.',i,i);
      vfmt_$ws2(stream_$errout,'                   BATCH  "netstat -a"%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'OPTIONS%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  -N nodeid     Execute the process on the given node.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'                Default if omitted:  Execute on current node%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  -PN name      Use given name as process name.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'                Default if omitted:  Use  BATCH.username.commandname%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  -L logfile    Direct output to given file.  Note that if no output%.',i,i);
      vfmt_$ws2(stream_$errout,'                is desired, logfile may be specified as /dev/null.%.',i,i);              
      vfmt_$ws2(stream_$errout,'                Please note also that with version 1.0 of BATCH, both standard%.',i,i);
      vfmt_$ws2(stream_$errout,'                and error output are written to the same log file, and that%.',i,i);
      vfmt_$ws2(stream_$errout,'                this log file also includes the commands executed.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'                Default if omitted:  Use  commandname.log in current%.',i,i);
      vfmt_$ws2(stream_$errout,'                working directory.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'  -Silent       Don''t tell me about the process to be created%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'PROBLEMS, RESTRICTIONS%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'   1. Error reporting is minimal.  The following errors are not%.',i,i);
      vfmt_$ws2(stream_$errout,'      reported;%.',i,i);
      vfmt_$ws2(stream_$errout,'       a.  pname same as another process%.',i,i);
      vfmt_$ws2(stream_$errout,'       b.  log file same as that of another process%.',i,i);
      vfmt_$ws2(stream_$errout,'       c.  command doesn''t exist%.',i,i);
      vfmt_$ws2(stream_$errout,'       d.  logfile or process name invalid%.',i,i);
      vfmt_$ws2(stream_$errout,'       e.  remote node not set up for remote server processes%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'   2. Ideally we''d like to transfer across csr to background%.',i,i);
      vfmt_$ws2(stream_$errout,'       process.  Currently only wd is transferred across directly.  The%.',i,i);
      vfmt_$ws2(stream_$errout,'       user could customize by adding a startup script.  The aim here%.',i,i);
      vfmt_$ws2(stream_$errout,'       would be:  If we can type a command at the shell level, we can%.',i,i);
      vfmt_$ws2(stream_$errout,'       precede the command by "batch" and achieve the same results.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'EXAMPLES%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'    1.  $ BATCH pas myfile%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'             This creates a process to compile the file myfile.pas%.',i,i);
      vfmt_$ws2(stream_$errout,'             in the current directory.  The process name will be%.',i,i);
      vfmt_$ws2(stream_$errout,'             batch.slp.pas, and the log file will be pas.log%.',i,i);
      vfmt_$ws2(stream_$errout,'             in the current working directory.%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'    2.  $ BATCH my_shell_script -n 2846%.',i,i);
      vfmt_$ws2(stream_$errout,'%.',i,i);
      vfmt_$ws2(stream_$errout,'             This process is created on another node.%.',i,i);
    end; {output_help}

  procedure get_arguments;

    var arg_no: integer;
        arg: pathtype;
        misc_status: status_$t;
        i,j: integer; {loop counters}

    procedure get_switch;

      begin {get_switch}
        for i := 1 to arg.length do   {Convert to lower case}
          if (arg.name[i] >= 'A') and (arg.name[i] <= 'Z')  then
            arg.name[i] := chr (ord (arg.name[i]) + 32);
        if (arg.name[2] = 'h') then begin
          output_help;
          pgm_$exit;
        end else if (arg.name[2] = 'p') then begin
          arg_no := arg_no + 1;
          process_name.length := pgm_$get_arg( arg_no, process_name.name, 
                                             misc_status, name_$pnamlen_max);
          name_specified := true;
        end else if ((arg.name[2] = 'o') or (arg.name[2] = 'n')) then begin
          arg_no := arg_no + 1;
          node_id.length := pgm_$get_arg( arg_no, node_id.name, 
                                             misc_status, name_$pnamlen_max);
          node_specified := true;
        end else if (arg.name[2] = 'l') then begin
          arg_no := arg_no + 1;
          logfile_name.length := pgm_$get_arg( arg_no, logfile_name.name, 
                                             misc_status, name_$pnamlen_max);
          logfile_specified := true;
        end else if (arg.name[2] = 's') then begin
          silent_specified := true;
        end else begin
          vfmt_$ws2(stream_$errout,'?Unrecognized switch %A%.',arg.name, arg.length);
          pgm_$exit;
        end; {case if on switch type}
      end; {get_switch}

    begin {get_arguments}
      for arg_no := 1 to max_arguments do begin
        arg.length := pgm_$get_arg( arg_no, arg.name, misc_status, 
                                    name_$pnamlen_max);
        if (arg.length > 0) then begin
          if (arg.name[1] = '-') then {if it's a switch}
            get_switch
          else begin           {if not a switch, assume must be written to command}
            for i := 1 to arg.length do begin
              write(arg.name[i]);
            end;
            write(' ');
            if not command_specified then begin  {if first non-switch, parse off leaf as command}
              j := 0;
              i := 0;
              while (i<arg.length) do begin
                j := j + 1;
                i := i + 1;
                if arg.name[i] = '/' then
                  j := 0
                else if arg.name[i] = ' ' then begin
                  i := arg.length;
                  j := j - 1;
                end else begin
                  command.name[j] := arg.name[i];
                end;
              end; {for i implemented as while i}
              command.length := j;
              command_specified := true;
            end; {if not command_specified}
          end; {if switch then else}
        end; {if non-null arg}
      end {for arg_no}
    end; {get_arguments}

  procedure get_procinfo;

    {Here we first get the full SID text, then parse off the first part
     for username.  Next we get the working directory}

    var i: integer;

    begin {get_procinfo}
      pm_$get_sid_txt(256,username.name,username.length);
      i := 1;
      while ((i <= username.length) and (username.name[i] <> '.')) do begin
        i := i + 1;
      end;
      username.length := i - 1;
      name_$get_wdir(wd.name,wd.length,misc_status);
      for i := 1 to wd.length do begin
        if (wd.name[i] >= 'A') and (wd.name[i] <= 'Z')  then
            wd.name[i] := chr (ord (wd.name[i]) + 32);
      end;
    end; {get_procinfo}

  procedure do_logfile;

    var i_full: integer;  {location in full_log name}

    begin
      if (not silent_specified) then begin
        vfmt_$ws2(stream_$errout,'Working directory of created process will be %A%.',wd.name,wd.length);
      end;
      if logfile_specified then begin
        if logfile_name.name[1] = '/' then begin
          if ((logfile_name.name[2] <> '/') and node_specified) then begin
            vfmt_$ws2(stream_$errout,'?Warning: logfile specification begins with ''/''%.', i,i);
          end;
          for i_full := 1 to logfile_name.length do begin
            full_log.name[i_full] := logfile_name.name[i_full];
          end;
          full_log.length := logfile_name.length;
        end else begin
          for i_full := 1 to wd.length do begin
            full_log.name[i_full] := wd.name[i_full];
          end;
          full_log.name[wd.length+1] := '/';
          for i_full := wd.length+2 to (wd.length + logfile_name.length+1) do begin
            full_log.name[i_full] := logfile_name.name[i_full-wd.length-1];
          end;
          full_log.length := wd.length + logfile_name.length + 1;
        end;
      end else begin
        for i_full := 1 to wd.length do begin
          full_log.name[i_full] := wd.name[i_full];
        end;
        full_log.name[wd.length+1] := '/';
        for i_full := wd.length+2 to (wd.length + command.length + 1) do begin
          full_log.name[i_full] := command.name[i_full - wd.length-1];
        end;
        i_full := wd.length + command.length + 1;
        full_log.name[i_full+1] := '.';
        full_log.name[i_full+2] := 'l';
        full_log.name[i_full+3] := 'o';
        full_log.name[i_full+4] := 'g';
        full_log.length := wd.length + command.length + 5;
      end; {if specified else endif}
      if (not is_null(full_log)) then begin   {If we haven't specified /dev/null as the filename}
        if (exists(full_log)) then begin
          vfmt_$ws2(stream_$errout,'?logfile %A already exists.%.',full_log.name,full_log.length);
          pgm_$exit;
        end;
        write('@'' -l ');
        for i := 1 to full_log.length do write(full_log.name[i]);
        write('''');
        if (not silent_specified) then begin
          vfmt_$ws2(stream_$errout,'Logfile will be %A%.',full_log.name,full_log.length);
        end;
      end else begin  {else it was /dev/null}
        write('@''''');
        if (not silent_specified) then begin
          vfmt_$ws2(stream_$errout,'Logfile will not be created%.',0,0);
        end;
      end; {if not /dev/null else}
    end;


  procedure do_name;

    var i: integer;

    begin
      write(' -n ');
      if name_specified then begin
        for i := 1 to process_name.length do write(process_name.name[i]);
        if (not silent_specified) then begin
          vfmt_$ws2(stream_$errout,'Process name will be %A%.',process_name.name,process_name.length);
        end;
      end else begin
        write('batch.');
        for i := 1 to username.length do write(username.name[i]);
        write('.');
        for i := 1 to command.length do write(command.name[i]);
        if (not silent_specified) then begin
          vfmt_$ws5(stream_$errout,'Process name will be batch.%A.%A%.',username.name,username.length,command.name,command.length,0);
        end;
      end;
    end;

  procedure do_nodeid;

    var i: integer;

    begin
      write (' -on ');
      for i := 1 to node_id.length do write(node_id.name[i]);
      writeln(' -cps -me');
      if (not silent_specified) then begin
        if (node_specified) then begin
          vfmt_$ws2(stream_$errout,'Process will be created on node %A%.',node_id.name,node_id.length);
        end else begin
          vfmt_$ws2(stream_$errout,'Process will be created on this node.%.',0,0);
        end;
      end;
    end;

  begin {parse_batch main}
    init_globals;
    get_procinfo;
    start_output;
    get_arguments;
    if not command_specified then begin
      vfmt_$ws2(stream_$errout,'?No command specified%.', i,i);
      pgm_$exit;
    end;
    do_logfile;
    do_name;
    do_nodeid;
  end. {parse_batch main}
SHAR_EOF
chmod +x 'parse_batch.pas'
fi # end of overwriting check
if test -f 'sh_log.pas'
then
	echo shar: will not over-write existing file "'sh_log.pas'"
else
cat << \SHAR_EOF > 'sh_log.pas'
program shell_with_log;

{ Author:  Steven Pucci,  Mentor APD
  Date:    May 29, 1985

  This program is functionally equivalent to the /com/sh program, with
  the exception that it directs both error and standard output to a
  file specified with the -l argument.  It parses off the -l logname
  arguments from its own argument list, opens the specified file,
  and invokes /com/sh with the remaining arguments.  It passes the
  stream number for the opened file to both error output and standard
  output for the invoked program.  This program should work even if
  /com/sh is changed substantially, since the real /com/sh is invoked
  to do the real work.  The only change to /com/sh which would
  necessitate recompiling this program would be the addition of an
  argument to /com/sh which starts with -l. }
 
  %include '/sys/ins/base.ins.pas';
  %include '/sys/ins/error.ins.pas';
  %include '/sys/ins/pgm.ins.pas';
  %include '/sys/ins/streams.ins.pas';
  %include '/sys/ins/vfmt.ins.pas';

  const program_version = 1.1;

     {History:      1.1     2/12/86    slp    Allowed sh_log with no -l to invoke sh transparently so the "batch -l /dev/null" command will work}

  type pathtype = record
                    name: name_$pname_t;
                    length: integer
                  end;

  var  status:  status_$t;
       stream_id:  stream_$id_t; {stream id of log file}
       ec:  uid_$t; {reserved -- no documentation}
       stream_vector: array[1..4] of stream_$id_t; {to pass to /com/sh}
       wait_mode: pgm_$mode;      {of invoke of /com/sh}
       logfile_name: pathtype;
       logfile_specified: boolean;
       argument_vector_pointer: pgm_$argv_ptr;
       num_args: integer;
       arg: pathtype;  {holds arguments for comparison}

  procedure output_help;

    begin {output_help}
      vfmt_$write2('sh_log (shell_with_log_file) revision %3.1F, 85/3/xx%.',program_version,0);
      writeln('SH_LOG');
      writeln('  Author:   Steve Pucci at Mentor APD');
      writeln;
      writeln('This program is functionally equivalent to the sh program, with one exception:');
      writeln('there is an additional switch option to create a log file.  All other options');
      writeln('to sh are available; type HELP SH for details on the other options.  Please note');
      writeln('that this program is most useful when run as a background process.');
      writeln;
      writeln('FORMAT:');
      writeln;
      writeln('   sh_log  [options to the sh command]  -l logfilename');
      writeln;
      writeln('OPTIONS:');
      writeln;
      writeln('   -l  logfilename        The name of a file to be created which will contain');
      writeln('                          all standard and error output from the shell program.');
      writeln('                          Note that if the -v switch is also specified, the');
      writeln('                          commands executed by the shell program will also be');
      writeln('                          written to the logfile.');
      writeln;
      writeln('   all options to sh      See HELP SH for details.');
      writeln;
      writeln;
      writeln('EXAMPLES:');
      writeln;
      writeln('   1.  sh_log  pas myfile  -l myfilename');
      writeln;
      writeln('         Executes the shell command "pas myfile," and directs the output to the');
      writeln('         file myfilename.');
      writeln;
      writeln('   2.  sh_log   myscript  -v  -l  myfilename');
      writeln;
      writeln('         Executes the shell script myscript, and directs the output to the file');
      writeln('         myfilename.  Note that since -v is specified, the commands in myscript');
      writeln('         are also written to the file.');
    end; {output_help}

  procedure parse_arguments;

  { The idea is to pass everything through to /com/sh, with the
    exception of the -l logfile argument which we strip off, and
    the -h argument for help.
    The strange loop logic is necessary to retrieve the arguments
    properly.  We need to get num_args arguments, but the argument
    pointer changes as we delete arguments from the vector.  See
    the description of the pgm routines for details. }

    var i: integer; {loop counter}
        arg_no: integer; {argument number}

    begin {parse_arguments}
      logfile_specified := false;
      pgm_$get_args( num_args, argument_vector_pointer );
      i := 0;  {i is number of arguments retrieved so far}
      arg_no := 1; {arg_no is pointer to next argument -- no, I can't do this with one loop variable}
      while (i < num_args-1) do begin  {the 0th arg is the program name}
        arg.length := pgm_$get_arg( arg_no, arg.name, status, name_$pnamlen_max );
        if ( (arg.name[1] = '-') and ((arg.name[2] = 'l') or (arg.name[2] = 'L'))) then begin
          if logfile_specified then begin
            vfmt_$ws2(stream_$errout,'?More than one logfile specified%.',0,0);
            pgm_$exit;
          end; {if more than one logfile}
          pgm_$del_arg(arg_no);  {remove the -l from the arg list}
          logfile_name.length := pgm_$get_arg(arg_no, logfile_name.name, status, name_$pnamlen_max );
          if (status.all <> status_$ok) then begin
            vfmt_$ws2(stream_$errout,'?Trouble getting logfile argument%.',0,0);
            error_$print(status);
          end;
          logfile_specified := true;
          pgm_$del_arg(arg_no);  {remove the logfile name from the arg list}
          i := i + 2;  {we already did two more args}
        end else if ( (arg.name[1] = '-') and ((arg.name[2] = 'h') or (arg.name[2] = 'H'))) then begin
          output_help;
          pgm_$exit;
        end else begin  {if not the -l or the -h argument, increment arg ptr}
          arg_no := arg_no + 1;
          i := i + 1;
        end; {if it was the -l argument}
      end;  {while loop on argument number}
      if not logfile_specified then begin
        vfmt_$ws2(stream_$errout,'?No logfile specified -- use /com/sh; continuing anyway...%.',0,0);
{        pgm_$exit;  We want it to continue anyway so that batch works properly when /dev/null is specified}
      end; {if no logfile specified}
    end; {parse_arguments}

  procedure open_logfile;

    begin {open_logfile}
      stream_$create(logfile_name.name, logfile_name.length, stream_$write, stream_$unregulated, 
                     stream_id, status);
      if status.all <> status_$ok then begin
        vfmt_$ws2(stream_$errout,'?Trouble creating file %A%.',
                  logfile_name.name, logfile_name.length);
        error_$print(status);
        pgm_$exit;
      end;
    end; {open_logfile}

  procedure invoke_shell;

    begin {invoke shell}
      stream_vector[1] := stream_$stdin;  {std input for /com/sh}
      stream_vector[3] := stream_$errin;  {err input for /com/sh}
      if logfile_specified then begin
        stream_vector[2] := stream_id;      {std output for /com/sh}
        stream_vector[4] := stream_id;      {err output for /com/sh}
        num_args := num_args - 2;     {leave off file specification}
      end else begin
        stream_vector[2] := stream_$stdout; {std output for /com/sh}
        stream_vector[4] := stream_$errout; {err output for /com/sh}
      end;
      wait_mode := [pgm_$wait];
      pgm_$invoke('/com/sh', 7, num_args, argument_vector_pointer^, 4, stream_vector, wait_mode, ec, status );
      if status.all <> status_$ok then begin
        vfmt_$ws2(stream_$errout,'?Trouble with invoke of /com/sh%.',0,0);
        error_$print(status);
        pgm_$exit;
      end;
    end; {invoke shell}

  begin {shell_with_log}
    parse_arguments;
    if logfile_specified then
      open_logfile;
    invoke_shell;
  end.  {shell_with_log}
SHAR_EOF
chmod +x 'sh_log.pas'
fi # end of overwriting check
if test -f 'a.readme'
then
	echo shar: will not over-write existing file "'a.readme'"
else
cat << \SHAR_EOF > 'a.readme'
written by : Steve Pucci
Mentor Graphics
408-436-1500 


DESCRIPTION:
  The batch command allows you to SIMPLY create a batch process on a
node, either the local one or a remote one.  Simply typing
  BATCH shell-script-name
invokes a batch job on the local node; parameters can be specified to
run on another node.

This command is useful primarily for
  1.  People who wish to run long overnight jobs without staying logged
      in, and
  2.  People who log in over SIO lines and want to run more than one
      process at the same time.

The BATCH.HLP file is just a copy of what happens if you type
  BATCH -H
 

REQUIRED FILES:

The "batch" set contains the following files:
  1.  The batch shell script (a one-line file)
  2.  The parse_batch.bin file (parses the batch command)
  3.  The parse_batch.pas file (source for parse_batch.bin)
  4.  The sh_log file (runs a shell script, directing both standard
                       and error output to the same logfile)
  5.  The sh_log.pas file (source for sh_log)
  6.  The batch.hlp file (copy of the help for BATCH).
  7.  The a.readme file (this file)


INSTALLATION:

  1.  Place parse_batch.bin in an appropriate place on the network
      (anywhere executables are stored; can be user directory)
  2.  Edit batch and change the reference to parse_batch.bin to
      reflect the correct location of parse_batch.bin
  3.  Put batch somewhere in your command search rules
  4.  Put sh_log in /com on all nodes that will have batch jobs
      running on them.  (If you want to put sh_log somewhere other
      than /com, you need to edit parse_batch.pas, and change
      the reference to /com/sh_log to wherever you want to put it.
      Then you would need to recompile parse_batch with the Pascal
      compiler).
  5.  Type batch -help for details on how to use it.

SHAR_EOF
chmod +x 'a.readme'
fi # end of overwriting check
if test -f 'batch.hlp'
then
	echo shar: will not over-write existing file "'batch.hlp'"
else
cat << \SHAR_EOF > 'batch.hlp'
batch revision 1.35, 85/5/xx by SLP at Mentor APD
BATCH  --  submit a command as a background (CPS) process
usage:  BATCH  pathname  [-N nodeid] [-PN process_name]
                         [-L logfile] [-Silent]



FORMAT

  BATCH  pathname 


  BATCH creates a background process on the given node and has the
  process execute the given command.  The process executes with the same
  id as the calling process, in the same working directory as the process.


ARGUMENTS

  pathname      The shell command to be executed.  This may be any
                command recognized by the command interpreter; thus
                it may be a shell script or an object file.
                If the command has arguments, enclose the command
                AND any arguments in quotes.  For example:
                   BATCH  "netstat -a"


OPTIONS

  -N nodeid     Execute the process on the given node.

                Default if omitted:  Execute on current node

  -PN name      Use given name as process name.

                Default if omitted:  Use  BATCH.username.commandname

  -L logfile    Direct output to given file.  Note that if no output
                is desired, logfile may be specified as /dev/null.
                Please note also that with version 1.0 of BATCH, both standard
                and error output are written to the same log file, and that
                this log file also includes the commands executed.

                Default if omitted:  Use  commandname.log in current
                working directory.

  -Silent       Don't tell me about the process to be created


PROBLEMS, RESTRICTIONS

   1. Error reporting is minimal.  The following errors are not
      reported;
       a.  pname same as another process
       b.  log file same as that of another process
       c.  command doesn't exist
       d.  logfile or process name invalid
       e.  remote node not set up for remote server processes

   2. Ideally we'd like to transfer across csr to background
       process.  Currently only wd is transferred across directly.  The
       user could customize by adding a startup script.  The aim here
       would be:  If we can type a command at the shell level, we can
       precede the command by "batch" and achieve the same results.

EXAMPLES

    1.  $ BATCH pas myfile

             This creates a process to compile the file myfile.pas
             in the current directory.  The process name will be
             batch.slp.pas, and the log file will be pas.log
             in the current working directory.

    2.  $ BATCH my_shell_script -n 2846

             This process is created on another node.
SHAR_EOF
chmod +x 'batch.hlp'
fi # end of overwriting check
if test -f 'batch.bld'
then
	echo shar: will not over-write existing file "'batch.bld'"
else
cat << \SHAR_EOF > 'batch.bld'
von

pas parse_batch.pas
bind -b parse_batch parse_batch.bin
dlf parse_batch.bin

pas sh_log.pas
bind -b sh_log sh_log.bin
dlf sh_log.bin

voff
SHAR_EOF
chmod +x 'batch.bld'
fi # end of overwriting check
if test -f 'parse_batch'
then
	echo shar: will not over-write existing file "'parse_batch'"
else
cat << \SHAR_EOF > 'parse_batch'
J J"d$*%%B'Hm
lHz& m
rHzv m
HzF m
tHz. m
DHz~ m
PHzV m
dHz m
HzrN/HzHHzm m
EXISTShe
IS_NULL>x
START_OUTPUTx

(OUTPUT_HELPF

GET_SWITCH
.i

GET_ARGUMENTS.
(GET_PROCINFO1

DO_LOGFILElPC


(DO_NAMEZ
((("	DO_NODEID6
$&PARSE_BATCHV$XPARSE_BATCH                     21wS  "d |!PROCEDURE$                      	$DATA$                           .DEBUG$                          PAS_$WRITELN                    `VFMT_$WS5 




                      0NAME_$GET_WDIR                  PM_$GET_SID_TXT                 PPGM_$GET_ARG                    	 PGM_$EXIT                       
pVFMT_$WS2                       @PAS_$WRITE                      STREAM_$INQUIRE                 
`PAS_$OUTPUT                     X
 &*06:@FJPVZ`fjpvz
SHAR_EOF
chmod +x 'parse_batch'
fi # end of overwriting check
if test -f 'batch.install'
then
	echo shar: will not over-write existing file "'batch.install'"
else
cat << \SHAR_EOF > 'batch.install'
von
cpf batch /users/userlib/com/batch -r -f -du
cpf parse_batch /users/userlib/com/parse_batch -r -f -du

cpf sh_log //bert/com/sh_log -r -f -du
cpf sh_log //ernie/com/sh_log -r -f -du
cpf sh_log //tigger/com/sh_log -r -f -du
cpf sh_log //bertha/com/sh_log -r -f -du
cpf sh_log //piggy/com/sh_log -r -f -du
cpf sh_log //winnie/com/sh_log -r -f -du
cpf sh_log //oscar/com/sh_log -r -f -du
cpf sh_log //eeyore/com/sh_log -r -f -du

cpf batch.hlp //bert/sys/help/batch.hlp -r -f -du
cpf batch.hlp //ernie/sys/help/batch.hlp -r -f -du
cpf batch.hlp //tigger/sys/help/batch.hlp -r -f -du
cpf batch.hlp //bertha/sys/help/batch.hlp -r -f -du
cpf batch.hlp //piggy/sys/help/batch.hlp -r -f -du
cpf batch.hlp //winnie/sys/help/batch.hlp -r -f -du
cpf batch.hlp //oscar/sys/help/batch.hlp -r -f -du
cpf batch.hlp //eeyore/sys/help/batch.hlp -r -f -du
voff
SHAR_EOF
chmod +x 'batch.install'
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0