SunGrid launcher support

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

lint fixes

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

fix lint issues

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

add open source header

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

update message in SGE.py and a comment in SgeLauncher.py

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

closing the log file

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

update SGE lower case and strings

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

update SGE PR

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Resolving comments

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix lint issues

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SGE lint issue

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SGE lint indent issue

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SGE lint indent issue2

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SGE lint indent issue3

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SGE comments 3-Aug

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix SgeLauncher

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Resolve SGE PR comments

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Remove trailing spaces

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix lint issues

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Fix latest comments

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>

Update exception description

Signed-off-by: Sharon Topaz <sharon.topaz@nuvoton.com>
diff --git a/util/dvsim/LauncherFactory.py b/util/dvsim/LauncherFactory.py
index 6d60868..3829187 100644
--- a/util/dvsim/LauncherFactory.py
+++ b/util/dvsim/LauncherFactory.py
@@ -8,6 +8,7 @@
 from Launcher import Launcher
 from LocalLauncher import LocalLauncher
 from LsfLauncher import LsfLauncher
+from SgeLauncher import SgeLauncher
 
 try:
     from edacloudlauncher.EdaCloudLauncher import EdaCloudLauncher
@@ -41,6 +42,9 @@
     elif launcher == "lsf":
         _LAUNCHER_CLS = LsfLauncher
 
+    elif launcher == "sge":
+        _LAUNCHER_CLS = SgeLauncher
+
     # These custom launchers are site specific. They may not be committed to
     # the open source repo.
     elif launcher == "edacloud" and EDACLOUD_LAUNCHER_EXISTS:
diff --git a/util/dvsim/SGE.py b/util/dvsim/SGE.py
new file mode 100755
index 0000000..2086b78
--- /dev/null
+++ b/util/dvsim/SGE.py
@@ -0,0 +1,349 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+# ----------------------------------
+# SGE.py
+#       _JobData Class
+# ----------------------------------
+import logging
+import pwd
+import os
+import re
+import subprocess
+import time
+
+#
+from qsubopts import qsubOptions
+sgeJob_t = qsubOptions()
+
+
+class _JobData:
+    """
+    Internal helper class to manage job data from qstat
+    """
+    def __init__(self, qstat_job_line):
+        # The format of the line goes like
+        # job-ID prior name  user  state submit/start at queue slots ja-task-ID
+
+        tokens = qstat_job_line.split()
+
+        assert len(tokens) >= 8, 'Not a valid qstat line: ' + qstat_job_line
+        # Job line must have at least 8 tokens
+        try:
+            self.id = int(tokens[0])
+        except ValueError:
+            error_msg = "Could not convert data to an integer."
+            raise ValueError(error_msg)
+        self.priority = float(tokens[1])
+        self.name = tokens[2]
+        self.user = tokens[3]
+        self.state = tokens[4]
+        self.time = ' '.join(tokens[5:7])
+
+        if '@' in qstat_job_line:
+            # Has queue assigned, e.g. core2.q@q2.caspian.mit.edu
+            self.queue = tokens[7]
+            self.slots = tokens[8]
+            if len(tokens) == 9:
+                self.ja_task_id = None
+            elif len(tokens) == 10:
+                self.ja_task_id = tokens[-1]
+            else:
+                raise ValueError(f"Could not parse line: {qstat_job_line}")
+        else:
+            # No queue assigned
+            self.slots = tokens[7]
+            if len(tokens) == 8:
+                self.ja_task_id = None
+            elif len(tokens) == 9:
+                self.ja_task_id = tokens[-1]
+            else:
+                raise ValueError(f"Could not parse line: {qstat_job_line}")
+
+        # Convert array indices ja_task_id into python list format
+        ja_task_id = []
+        if self.ja_task_id is not None:
+            for blob in self.ja_task_id.split(','):
+                # Parse data of form '193-349:1' or '1934'
+                x = blob.split(':')
+                if len(x) == 1:
+                    ja_task_id += x
+                else:
+                    subjobs, step = x
+                    begin, end = subjobs.split('-')
+                    ja_task_id += range(int(begin), int(end) + 1, int(step))
+
+        self._ja_tasklist = ja_task_id
+
+    def __repr__(self):
+        repr = ['{']
+        for key, value in self.__dict__.items():
+            if key[0] != '_':
+                repr.append(key + '=' + str(value))
+        repr.append('}')
+        return '\n'.join(repr)
+
+
+class JobList:
+    """
+    Internal helper class to manage job lists
+    """
+
+    def __init__(self, qstat_output=None):
+        self._joblist = []
+        for line in qstat_output.split('\n')[2:-1]:
+            self._joblist.append(_JobData(line))
+
+    def __iter__(self):
+        for job in self._joblist:
+            yield job
+
+    def __repr__(self):
+        return '\n'.join([str(job) for job in self._joblist])
+
+
+class SGE:
+    """External system call handler for Sun Grid Engine environment."""
+
+    def __init__(self, q=None, path='', ):
+
+        logger = logging.getLogger('SGE.__init__')
+
+        if q is None:
+            # No queue specified. By default, submit to all available queues.
+            self.cmd_qconf = os.path.join(path, 'qconf')
+
+            try:
+                qliststr = _exec(self.cmd_qconf + ' -sql')
+            except IOError:
+                error_msg = 'Error querying queue configuration'
+                logger.error(error_msg)
+                raise IOError(error_msg)
+
+            self.q = qliststr.replace('\n', ',')[:-1]
+
+            logger.info("""Sun Grid Engine handler initialized
+Queues detected: %s""", self.q)
+
+        else:
+            self.q = q
+
+        self.cmd_qsub = os.path.join(path, 'qsub')
+        self.cmd_qstat = os.path.join(path, 'qstat')
+
+    def wait(self, jobid, interval=10, name=None, pbar=None,
+             pbar_mode=None):
+        """Waits for job running on SGE Grid Engine environment to finish.
+
+        If you are just waiting for one job, this becomes a dumb substitute for
+        the -sync y option which can be specified to qsub.
+
+        Inputs:
+
+        jobid
+        interval - Polling interval of SGE queue, in seconds. (Default: 10)
+        """
+
+        logger = logging.getLogger('SGE.wait')
+
+        dowait = True
+        while dowait:
+            p = subprocess.Popen(self.cmd_qstat, shell=True,
+                                 stdout=subprocess.PIPE)
+            pout, _ = p.communicate()
+
+            if pbar is not None:
+                logger.error('Progress bar handling not implemented')
+
+            dowait = False
+            for line in pout.split('\n'):
+                t = line.split()
+                if len(t) >= 5 and t[0] == str(jobid):
+                    # Find a line with useful info
+                    if re.search(t[4], 'qwrt'):
+                        # Job must be queued, running or being transferred
+                        dowait = True
+                        break
+                    if re.search(t[4], 'acuE'):
+                        # Job or host in error state
+                        logger.warning('Job %d in error state', str(jobid))
+
+            if dowait:
+                time.sleep(interval)
+                if name is None:
+                    logger.info("Time %s: waiting for jobid %s to finish",
+                                time.ctime(), str(jobid))
+                else:
+                    logger.info("Time %s: waiting for job '%s' (jobid %s) to \
+finish", time.ctime(), name, str(jobid))
+
+    def submit(self, job, array=False, useenvironment=True, usecwd=True,
+               name=None, stdin=None, stdout=None, stderr=None,
+               joinstdouterr=True, nproc=1, wait=True, lammpi=True):
+        """
+        Submits a job to SGE
+        Returns jobid as a number
+        """
+
+        logger = logging.getLogger('SGE.submit')
+
+        logger.info("Submitting job:   " + str(job) + " stdout: %s \
+Stderr: %s", stdout, stderr)
+
+        # Parameters to qsub specified as the header of the job specified on
+        # STDIN
+        lamstring = lammpi and f" -pe lammpi {nproc}" or ""
+        qsuboptslist = ['-cwd -V ', lamstring]
+
+        if name is not None:
+            qsuboptslist.append('-N ' + name)
+        if stdin is not None:
+            qsuboptslist.append('-i ' + stdin)
+        if stdout is not None:
+            qsuboptslist.append('-o ' + stdout)
+        if stderr is not None:
+            qsuboptslist.append('-e ' + stderr)
+        if joinstdouterr:
+            qsuboptslist.append('-j')
+        if wait:
+            qsuboptslist.append('-sync y')
+        if usecwd:
+            qsuboptslist.append('-cwd')
+        if useenvironment:
+            qsuboptslist.append('-V')
+        if array is not False:
+            try:
+                n = int(array[0])
+            except IndexError:
+                n = int(array)
+                raise IndexError("List is empty!")
+            except ValueError:
+                error_msg = "array[0] being an out of bounds access."
+                logger.error(error_msg)
+                raise ValueError(error_msg)
+            try:
+                m = int(array[1])
+            except ValueError:
+                m = None
+                raise ValueError("Could not convert data to an integer.")
+            except IndexError:
+                m = None
+                raise IndexError("array[1] being an out of bounds access.")
+            try:
+                s = int(array[2])
+            except IndexError:
+                s = None
+                raise IndexError("array[2] being an out of bounds access.")
+            except ValueError:
+                s = None
+                raise ValueError("Could not convert data to an integer.")
+            if m == s is None:
+                qsuboptslist.append('-t %d' % n)
+            elif s is None:
+                qsuboptslist.append('-t %d-%d' % (n, m))
+            else:
+                qsuboptslist.append('-t %d-%d:%d' % (n, m, s))
+
+        qsubopts = ' '.join(qsuboptslist)
+
+        pout = _exec(self.cmd_qsub, stdin=qsubopts + '\n' + job,
+                     print_command=False)
+
+        try:
+            # Next to last line should be
+            # "Your job 1389 (name) has been submitted"
+            # parse for job id
+            jobid = int(pout.split('\n')[-2].split()[2])
+            return jobid
+        # except (ValueErrorValueError, IndexError, AttributeError) (e):
+        except (ValueError, IndexError, AttributeError):
+            error_msg = """Error submitting SGE job:
+%s
+%s
+
+Output was:
+%s""" % (qsubopts, job, pout)
+            logger.error(error_msg)
+            raise IOError(error_msg)
+
+    def getuserjobs(self, user=pwd.getpwuid(os.getuid())[0]):
+        """Returns a list of SGE jobids run by a specific user
+
+        Inputs
+            user - SGE user to poll (Default = '', i.e. current user)
+            qstat - path to qstat binary (Default = 'qstat')
+        """
+
+        p = subprocess.Popen(self.cmd_qstat + " -u " + user, shell=True,
+                             stdout=subprocess.PIPE)
+        qstat_output, _ = p.communicate()
+        joblist = JobList(qstat_output)
+        return [job for job in joblist if job.user == user]
+
+    def run_job(self, command, name='default', logfnm='default.log',
+                wait=True):
+        """Run job on SGE with piped logging."""
+        jobid = self.submit(command, name=name, stdout=logfnm,
+                            stderr=logfnm, wait=wait)
+        return jobid
+
+    def get_queue_instance_status(self):
+        """
+        Get loads for each queue instance
+        """
+        output = _exec(' '.join([self.cmd_qstat, '-f']))
+
+        data = []
+        for line in output.split('\n')[1:]:
+            t = line.split()
+            if len(t) != 5:
+                continue
+
+            nodename = t[0].split('@')[1].split('.')[0]
+            maxslots = int(t[2].split('/')[2])
+            load = float(t[3])
+
+            data.append({'name': nodename, 'maxslots': maxslots, 'load': load})
+
+        return data
+
+
+def _exec(command, print_to_screen=False, logfnm=None, stdin='',
+          print_command=False):
+    """
+    Runs command line using subprocess, optionally returning stdout
+    """
+    def _call_cmd(command, stdin=''):
+        p = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+        output, _ = p.communicate(stdin)
+        return output
+
+    logger = logging.getLogger('_exec')
+
+    if print_command:
+        logger.info("Executing process: \x1b[1;92m%-50s\x1b[0m Logfile: %s",
+                    command, logfnm)
+
+    output = ""
+    if logfnm is not None:
+        try:
+            with open(logfnm, 'a') as f:
+                if print_command:
+                    print(f, "Executing process: %s" % command)
+                output = _call_cmd(command, stdin)
+                f.write(output)
+        except IOError:
+            error_msg = 'Error: File: ' + str(logfnm) + ' does not appear to exist.'
+            logger.error(error_msg)
+            raise IOError(error_msg)
+    else:
+        output = _call_cmd(command, stdin)
+
+    logger.info('Output of command is:\n%s', output)
+
+    if print_to_screen:
+        print(output)
+
+    return output
diff --git a/util/dvsim/SgeLauncher.py b/util/dvsim/SgeLauncher.py
new file mode 100755
index 0000000..ad7c50e
--- /dev/null
+++ b/util/dvsim/SgeLauncher.py
@@ -0,0 +1,182 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+# ------------------------------------
+#      SgeLauncher Class
+#
+# ------------------------------------
+import os
+import shlex
+import subprocess
+from subprocess import PIPE, Popen
+
+import SGE
+from Launcher import ErrorMessage, Launcher, LauncherError
+
+global job_name
+
+pid = os.getpid()
+
+
+class SgeLauncher(Launcher):
+    """
+    Implementation of Launcher to launch jobs in the user's local workstation.
+    """
+
+    # Misc common SgeLauncher settings.
+    max_odirs = 5
+
+    def __init__(self, deploy):
+        '''Initialize common class members.'''
+
+        super().__init__(deploy)
+
+        # Popen object when launching the job.
+        self.process = None
+
+    def _do_launch(self):
+        global job_name
+        # Update the shell's env vars with self.exports. Values in exports must
+        # replace the values in the shell's env vars if the keys match.
+        exports = os.environ.copy()
+        if self.deploy.exports:
+            exports.update(self.deploy.exports)
+
+        # Clear the magic MAKEFLAGS variable from exports if necessary. This
+        # variable is used by recursive Make calls to pass variables from one
+        # level to the next. Here, self.cmd is a call to Make but it's
+        # logically a top-level invocation: we don't want to pollute the flow's
+        # Makefile with Make variables from any wrapper that called dvsim.
+        if 'MAKEFLAGS' in exports:
+            del exports['MAKEFLAGS']
+
+        self._dump_env_vars(exports)
+
+        try:
+            f = open(self.deploy.get_log_path(),
+                     "w",
+                     encoding="UTF-8",
+                     errors="surrogateescape")
+            f.write("[Executing]:\n{}\n\n".format(self.deploy.cmd))
+            f.flush()
+            # ---------- prepare SGE job struct -----
+            sgeJob = SGE.qsubOptions()
+            sgeJob.args.N = 'VCS_RUN_' + str(pid)  # Name of Grid Engine job
+            if "build.log" in self.deploy.get_log_path():
+                sgeJob.args.N = 'VCS_BUILD_' + str(
+                    pid)  # Name of Grid Engine job
+
+            job_name = sgeJob.args.N
+            sgeJob.args.t = '0'  # Define an array job with 20 subjobs
+            sgeJob.args.slot = '1'  # Define num of slot
+            sgeJob.args.sync = 'y'  # wait for job to complete before exiting
+            sgeJob.args.q = 'vcs_q'  # Define the sge queue name
+            sgeJob.args.p = '0'  # Set priority to 0
+            sgeJob.args.ll = 'mf=20G'  # memory req,request the given resources
+            # pecifies a range of priorities from -1023 to 1024.
+            # The higher the number, the higher the priority.
+            # The default priority for jobs is zero
+            sgeJob.args.command = '"' + self.deploy.cmd + '"'
+            sgeJob.args.b = 'y'  # This is a binary file
+            sgeJob.args.o = self.deploy.get_log_path() + '.sge'
+            cmd = str(sgeJob.execute(mode='echo'))
+            # ---------------
+            self.process = subprocess.Popen(shlex.split(cmd),
+                                            bufsize=4096,
+                                            universal_newlines=True,
+                                            stdout=f,
+                                            stderr=f,
+                                            env=exports)
+            f.close()
+        except subprocess.SubprocessError as e:
+            raise LauncherError('IO Error: {}\nSee {}'.format(
+                e, self.deploy.get_log_path()))
+        finally:
+            self._close_process()
+
+        self._link_odir("D")
+        f.close()
+
+    def poll(self):
+        '''Check status of the running process
+
+        This returns 'D', 'P' or 'F'. If 'D', the job is still running. If 'P',
+        the job finished successfully. If 'F', the job finished with an error.
+
+        This function must only be called after running self.dispatch_cmd() and
+        must not be called again once it has returned 'P' or 'F'.
+        '''
+
+        assert self.process is not None
+        if self.process.poll() is None:
+            return 'D'
+        # -------------------------------------
+        # copy SGE jobb results to log file
+        if os.path.exists(self.deploy.get_log_path() + '.sge'):
+
+            file1 = open(self.deploy.get_log_path() + '.sge', 'r')
+            Lines = file1.readlines()
+            file1.close()
+            f = open(self.deploy.get_log_path(),
+                     "a",
+                     encoding="UTF-8",
+                     errors="surrogateescape")
+            for line in Lines:
+                f.write(line)
+            f.flush()
+            os.remove(self.deploy.get_log_path() + '.sge')
+            f.close()
+        # -------------------------------------
+
+        self.exit_code = self.process.returncode
+        status, err_msg = self._check_status()
+        self._post_finish(status, err_msg)
+        return status
+
+    def kill(self):
+        global job_name
+        '''Kill the running process.
+
+        This must be called between dispatching and reaping the process (the
+        same window as poll()).
+
+        '''
+        assert self.process is not None
+
+        # Try to kill the running process. Send SIGTERM first, wait a bit,
+        # and then send SIGKILL if it didn't work.
+        self.process.terminate()
+        try:
+            self.process.wait(timeout=2)
+        except subprocess.TimeoutExpired:
+            self.process.kill()
+            # ----------------------------
+            # qdel -f kill sge job_name
+            cmd = 'qstatus -a | grep ' + job_name
+            with Popen(cmd, stdout=PIPE, stderr=None, shell=True) as process:
+                output = process.communicate()[0].decode("utf-8")
+                output = output.rstrip("\n")
+                if output != '':
+                    output_l = output.split()
+                    cmd = 'qdel ' + output_l[0]
+                    with Popen(cmd, stdout=PIPE, stderr=None,
+                               shell=True) as process:
+                        output = process.communicate()[0].decode("utf-8")
+                        output = output.rstrip("\n")
+                        print('Killed job "' + str(output) + '"')
+            # ----------------------------
+        self._post_finish(
+            'K',
+            ErrorMessage(line_number=None, message='Job killed!', context=[]))
+
+    def _post_finish(self, status, err_msg):
+        super()._post_finish(status, err_msg)
+        self._close_process()
+        self.process = None
+
+    def _close_process(self):
+        '''Close the file descriptors associated with the process.'''
+
+        assert self.process
+        if self.process.stdout:
+            self.process.stdout.close()
diff --git a/util/dvsim/dvsim.py b/util/dvsim/dvsim.py
index b720e88..5bfb578 100755
--- a/util/dvsim/dvsim.py
+++ b/util/dvsim/dvsim.py
@@ -33,6 +33,7 @@
 import Launcher
 import LauncherFactory
 import LocalLauncher
+import SgeLauncher
 from CfgFactory import make_cfg
 from Deploy import RunTest
 from Timer import Timer
@@ -692,6 +693,7 @@
     # Register the common deploy settings.
     Timer.print_interval = args.print_interval
     LocalLauncher.LocalLauncher.max_parallel = args.max_parallel
+    SgeLauncher.SgeLauncher.max_parallel = args.max_parallel
     Launcher.Launcher.max_odirs = args.max_odirs
     LauncherFactory.set_launcher_type(args.local)
 
diff --git a/util/dvsim/qsubopts.py b/util/dvsim/qsubopts.py
new file mode 100755
index 0000000..97d6e9f
--- /dev/null
+++ b/util/dvsim/qsubopts.py
@@ -0,0 +1,1849 @@
+#!/usr/bin/env python
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+# -*- coding: utf-8 -*-
+# ----------------------------------
+# qsubOptions Class
+# ----------------------------------
+"""A helper class designed to handle the managment of options and
+positional arguments to qsub and related Grid Engine executables.
+
+Contains functions to write the requested execution string either
+to the command line or to a script file.
+"""
+
+import argparse
+
+
+class qsubOptions():
+    "A data type meant to collect qsub options. See man qsub for information"
+
+    def __init__(self, optstring='', prog='qsub'):
+        # Which SGE command are we going to work with?
+        self.prog = prog
+        sge_program_names = [
+            'qsub', 'qrsh', 'qsh', 'qlogin', 'qalter', 'qresub', 'qmake'
+        ]
+        assert self.prog in sge_program_names, 'Unsupported SGE command: ' + prog + \
+            'not one of ' + ', '.join(sge_program_names)
+
+        if prog == 'qmake' and '-pe' in optstring:
+            prog = 'qsub'
+        else:
+            prog = 'qrsh'
+
+        # SUPPRESS = If not specified, do not generate variable in namespace
+        self.parser = argparse.ArgumentParser(
+            description='Options to pass to qsub',
+            formatter_class=argparse.RawTextHelpFormatter,
+            argument_default=argparse.SUPPRESS,
+            epilog="""The following is scraped from the qsub manpage for GE \
+            6.2u5 dated 2009/12/01 12:24:06""")
+
+        # BEGIN SGE OPTION PARSER
+        # BUG if help still begins with a line with -option, have cosmetic bug where
+        # metavar cannot be specified correctly
+
+        yesno = ['y', 'yes', 'n', 'no']
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin']:
+            self.parser.add_argument('-@',
+                                     metavar='optionfile',
+                                     help="""\
+              Forces qsub, qrsh, qsh, or qlogin to use the options contained
+              in optionfile. The indicated file may contain all
+              valid options. Comment lines must start with a "#" sign.""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-a',
+                                     metavar='date_time',
+                                     help="""\
+              Available for qsub and qalter only.
+
+              Defines or redefines the time and date at  which  a  job  is  eligible
+              for  execution.  Date_time  conforms  to [[CC]]YY]MMDDhhmm[.SS],
+              for the details, please see Date_time in: sge_types(1).
+
+              If  this  option is used with qsub or if a corresponding value is specified
+              in qmon then a parameter named a and the value in the format CCYYMMDDhhmm.SS
+              will be passed to the defined JSV instances (see -jsv  option  below  or
+              find more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-ac',
+                                     metavar='variable[=value]',
+                                     action='append',
+                                     help=""" -ac variable[=value],...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Adds  the  given  name/value  pair(s)  to the job's context. Value may be omitted.
+              Grid Engine appends the given argument to the list of context variables for the job.
+              Multiple -ac, -dc, and -sc options may  be  given.   The order is important here.
+
+              The  outcome  of  the  evaluation  of all -ac, -dc, and -sc options or
+              corresponding values in qmon is passed to defined JSV instances as parameter
+              with the name ac.  (see -jsv option below or find more information concerning
+              JSV in jsv(1)) QALTER allows changing this option even while the job executes."""
+                                     )
+
+        if prog in ['qsub', 'qalter', 'qrsh', 'qsh', 'qlogin']:
+            self.parser.add_argument('-ar',
+                                     metavar='ar_id',
+                                     help="""\
+              Available for qsub, qalter, qrsh, qsh, or qlogin only.
+
+              Assigns  the  submitted  job  to  be  a  part of an existing Advance Reservation.
+              The complete list of existing
+              Advance Reservations can be obtained using the qrstat(1) command.
+
+              Note that the -ar option adds implicitly the -w e option if not otherwise requested.
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job however.
+
+              If  this  option  or  a  corresponding  value in qmon is specified
+              then this value will be passed to defined JSV instances as parameter
+              with the name ar.  (see -jsv option below or find  more  information
+              concerning  JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-A',
+                                     metavar='account_string',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Identifies the account to which the resource consumption of the
+              job should be charged. The account_string should
+              conform to the name definition in M sge_types 1 .
+              In the absence of this parameter Grid Engine will  place  the
+              default account string "ge" in the accounting record of the job.
+              Qalter allows changing this option even while the job executes.
+
+              If  this  option  or  a  corresponding  value in qmon is specified
+              then this value will be passed to defined JSV instances as parameter with the name A.
+              (see -jsv option below or  find  more  information  concerning  JSV  in jsv(1))"""
+                                     )
+
+        self.parser.add_argument('-binding',
+                                 nargs='+',
+                                 metavar=('binding_instance',
+                                          'binding_strategy'),
+                                 help="""\
+       -binding [ binding_instance ] binding_strategy
+
+              A  job  can  request a specific processor core binding (processor affinity)
+              with this parameter. This request is neither a hard nor a soft request,
+              it is a hint for the execution host to do this if possible.  Please note that
+              the  requested binding strategy is not used for resource  selection  within
+              Grid Engine.  As a result an execution host might be selected where Grid Engine
+              does not even know the hardware topology and therefore is not able
+              to apply the requested binding.
+
+              To enforce Grid Engine to select hardware on which the binding can be applied
+              please use the -l switch in combination with the complex attribute m_topology.
+
+              binding_instance is an optional parameter.
+              It might either be env, pe or set depending on which instance  should
+              accomplish the job to core binding. If the value for binding_instance
+              is not specified then set will be used.
+
+              env  means  that  the  environment variable SGE_BINDING will be exported
+              to the job environment of the job. This variable contains the selected
+              operating system internal processor numbers.  They might be  more  than  selected
+              cores  in  presence of SMT or CMT because each core could be represented
+              by multiple processor identifiers.  The processor numbers are space separated.
+
+              pe means that the information about the selected cores appears in
+              the fourth column of the pe_hostfile. Here the logical  core  and
+              socket numbers are printed (they start at 0 and have no holes)
+              in colon separated pairs (i.e. 0,0:1,0 which means core 0 on socket 0 and
+              core 0 on socket 1).  For more  information  about  the  $pe_hostfile
+              check ge_pe(5)
+
+              set (default if nothing else is specified). The binding strategy is applied
+              by Grid Engine. How this is achieved depends on the underlying hardware
+              architecture of the execution host where the submitted job will be started.
+
+              On Solaris 10 hosts a processor set will be created where the job can
+              exclusively run in.  Because of  operating system limitations at least
+              one core must remain unbound. This resource could of course used by an unbound job.
+
+              On  Linux  hosts  a  processor affinity mask will be set to restrict  the job
+              to run exclusively on the selected cores.
+              The operating system allows other unbound processes to use these cores.
+              Please note that on  Linux  the binding  requires  a  Linux  kernel
+              version of 2.6.16 or greater. It might be even possible to use a kernel with
+              lower version number but in that case additional kernel patches have to be
+              applied. The loadcheck  tool  in  the utilbin directory can be used to check
+              if the hosts capabilities.  You can also use the -sep in combination with
+              -cb of qconf(5) command to identify if Grid Engine is able to recognize the
+              hardware topology.
+
+              Possible values for binding_strategy are as follows:
+
+                  linear:<amount>[:<socket>,<core>]
+                  striding:<amount>:<n>[:<socket>,<core>]
+                  explicit:[<socket>,<core>;...]<socket>,<core>
+
+              For the binding strategy linear and striding there is an optional
+              socket and core pair attached.
+              These  denotes the mandatory starting point for the first core to bind on.
+
+              linear  means  that  Grid Engine tries to bind the job on amount successive cores.
+              If socket and core is omitted then Grid Engine first allocates successive cores
+              on the first empty socket found.  Empty means that  there  are
+              no  jobs bound to the socket by Grid Engine.  If this is not  possible or is
+              not sufficient Grid Engine tries to
+              find (further) cores on the socket with the most unbound cores and so on.
+              If the amount of allocated  cores  is
+              lower  than  requested  cores,  no binding is done for the job.
+              If socket and core is specified then Grid Engine
+              tries to find amount of empty cores beginning with this starting point.
+              If this is not possible then binding  is not done.
+
+              striding means that Grid Engine tries to find cores with a certain offset.
+              It will select amount of empty cores with a offset of n -1 cores in between.
+              Start point for the search algorithm is socket 0  core  0.  As  soon  as
+              amount  cores are found they will be used to do the job binding.
+              If there are not enough empty cores or if correct offset cannot be
+              achieved then there will be no binding done.
+
+              explicit binds the specified sockets and cores that  are  mentioned
+              in  the  provided  socket/core  list.  Each socket/core  pair  has to
+              be specified only once.If a socket/core pair is already in use by a different job the
+              whole binding request will be ignored.
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job, however.
+
+              If  this  option  or  a corresponding value in qmon is specified then these values
+              will be passe to defined JSV instances as parameters with the names binding_strategy,
+              binding_type, binding_amount,  binding_step,  binding_socket,
+              binding_core, binding_exp_n, binding_exp_socket<id>, binding_exp_core<id>.
+
+              Please  note that the length of the socket/core value list of the explicit binding is
+              reported as binding_exp_n.
+              <id> will be replaced by the position of the socket/core pair  within  the  explicit
+              list  (0  <=  id  <  binding_exp_n).   The first socket/core pair of the explicit
+              binding will be reported with the parameter names bind-
+              ing_exp_socket0 and binding_exp_core0.
+
+              Values that do not apply for the specified binding will not be reported to JSV.
+              E.g. binding_step will only  be
+              reported for the striding binding and all binding_exp_* values will passed to
+              JSV if explicit binding was speci‐
+              fied.  (see -jsv  option  below or find more information concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh']:
+            self.parser.add_argument('-b',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub, qrsh only. Qalter does not allow changing this option.
+              This option cannot be embedded in the script file itself.
+
+              Gives  the user the possibility to indicate explicitly whether command should be
+              treated as binary or script. If the value of -b is 'y', then command  may be a
+              binary or script.  The command might not be accessible  from  the
+              submission  host.   Nothing  except  the path of the command will be
+              transferred from the submission host to the
+              execution host. Path aliasing will be applied to the path of command
+              before command will be executed.
+
+              If the value of -b is 'n' then command needs to be a script and it will
+              be handled as script.  The  script  file
+              has to be accessible by the submission host.
+              It will be transferred to the execution host. qsub/qrsh will search
+              directive prefixes within script.
+
+              qsub will implicitly use -b n whereas qrsh will apply the -b y option
+              if nothing else is specified.
+
+              The value specified with this option or the corresponding value
+              specified in qmon will only be passed to defined
+              JSV instances if the value is yes.  The name of the parameter will be b.
+              The value will be y also when then long
+              form yes was specified during submission.
+              (see -jsv option below or find more  information  concerning  JSV  in
+              jsv(1))
+
+              Please  note  that  submission of command as script (-b n) can have a
+              significant performance impact,especially for short running jobs and big job scripts.
+              Script submission adds a number of  operations  to  the  submission
+              process: The job script needs to be
+              - parsed at client side (for special comments)
+              - transferred from submit client to qmaster
+              - spooled in qmaster
+              - transferred to execd at job execution
+              - spooled in execd
+              - removed from spooling both in execd and qmaster once the job is done
+              If job scripts are available on the execution nodes, e.g. via NFS, binary
+              submission can be the better choice.""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-c',
+                                     metavar='occasion_specifier',
+                                     help="""\
+              Available for qsub and qalter only.
+
+              Defines or redefines whether the job should be checkpointed, and if so,
+              under what circumstances. The specifica‐
+              tion of the checkpointing occasions with this option overwrites the
+              definitions of the  when  parameter  in  the
+              checkpointing  environment  (see  checkpoint(5)) referenced by the qsub
+              -ckpt switch.  Possible values for occa‐
+              sion_specifier are
+
+              n           no checkpoint is performed.
+              s           checkpoint when batch server is shut down.
+              m           checkpoint at minimum CPU interval.
+              x           checkpoint when job gets suspended.
+              <interval>  checkpoint in the specified time interval.
+
+              The minimum CPU interval is defined in the queue configuration (see
+              queue_conf(5) for details).  <interval>  has
+              to  be specified in the format hh:mm:ss.
+              The maximum of <interval> and the queue's minimum CPU interval is used
+              if <interval> is specified. This is done to ensure that a machine is not
+              overloaded by checkpoints being  generated too frequently.
+
+              The  value specified with this option or the corresponding value specified
+              in qmon will be passed to defined JSV
+              instances.  The <interval> will be available as parameter with the  name  c_interval.
+              The  character  sequence
+              specified will be available as parameter with the name c_occasion.
+              Please note that if you change c_occasion via
+              JSV then the last setting of c_interval will be overwritten and vice versa.
+              (see -jsv option below or find more
+              information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-ckpt',
+                                     metavar='ckpt_name',
+                                     help="""\
+              Available for qsub and qalter only.
+
+              Selects  the  checkpointing  environment (see checkpoint(5)) to be used
+              for checkpointing the job. Also declares the job to be a checkpointing job.
+
+              If this option or a corresponding value in qmon is specified then this
+              value  will  be  passed  to  defined  JSV
+              instances  as  parameter  with the name ckpt.  (see -jsv option below or
+              find more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']:
+            self.parser.add_argument('-clear',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh, and qlogin only.
+
+              Causes all elements of the job to be reset to the initial default
+              status prior to applying any modifications (if
+              any) appearing in this specific command.""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qalter']:
+            self.parser.add_argument('-cwd',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh and qalter only.
+
+              Execute  the  job  from  the  current  working directory.
+              This switch will activate Grid Engine's path aliasing
+              facility, if the corresponding configuration files are present (see ge_aliases(5)).
+
+              In the case of qalter, the previous definition of the current working
+              directory will be overwritten if qalter is
+              executed from a different directory than the preceding qsub or qalter.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified
+              then this value  will  be  passed  to  defined  JSV
+              instances  as  parameter with the name cwd. The value of this parameter
+              will be the absolute path to the current
+              working directory. JSV scripts can remove the path from jobs during the
+              verification  process  by  setting  the
+              value  of this parameter to an empty string.
+              As a result the job behaves as if -cwd was not specified during job
+              submission.  (see -jsv option below or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh']:
+            self.parser.add_argument('-C',
+                                     metavar='prefix_string',
+                                     help="""\
+              Available for qsub and qrsh with script submission (-b n).
+
+              Prefix_string defines the prefix that declares a directive in the  job's  command.
+              The  prefix  is  not  a  job
+              attribute,  but  affects  the  behavior  of  qsub  and qrsh.
+              If prefix is a null string, the command will not be
+              scanned for embedded directives.
+              The directive prefix consists of two ASCII characters which,
+              when appearing in the first two bytes of  a  script
+              line, indicate that what follows is an Grid Engine command.  The default is "#$".
+              The  user  should  be aware that changing the first delimiting character
+              can produce unforeseen side effects. If
+              the script file contains anything other than a "#" character in the first byte
+              position of the line,  the  shell
+              processor for the job will reject the line and may exit the job prematurely.
+              If the -C option is present in the script file, it is ignored."""
+                                     )
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-dc',
+                                     action='append',
+                                     metavar='variable',
+                                     help="""\
+       -dc variable,...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Removes  the  given  variable(s)  from the job's context.  Multiple -ac, -dc, and
+              -sc options may be given.  The order is important.
+
+              Qalter allows changing this option even while the job executes.
+
+              The outcome of the evaluation of all -ac, -dc, and -sc options or corresponding
+              values  in  qmon  is  passed  to
+              defined JSV instances as parameter with the name ac.  (see -jsv option below or
+              find more information concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsh', 'qrsh']:
+            self.parser.add_argument('-display',
+                                     metavar='display_specifier',
+                                     help="""\
+              Available for qsh and qrsh.
+
+              Directs xterm(1) to use display_specifier in order to contact the X server.
+              The display_specifier has  to  con‐
+              tain  the  hostname  part  of the display name (e.g. myhost:1).
+              Local display names (e.g. :0) cannot be used in
+              grid environments.  Values set with the -display option overwrite settings
+              from the submission  environment  and
+              from -v command line options.
+
+              If  this  option  or  a  corresponding  value in qmon is specified then this
+              value will be passed to defined JSV
+              instances as parameter with the name display. This value will also be available
+              in  the  job  environment  which
+              might  optionally  be  passed to JSV scripts. The variable name will be DISPLAY.
+              (see -jsv option below or find
+              more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-dl',
+                                     metavar='date_time',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Specifies the deadline initiation time in [[CC]YY]MMDDhhmm[.SS] format (see -a
+              option above). The deadline  ini‐
+              tiation time is the time at which a deadline job has to reach top priority to be
+              able to complete within a given
+              deadline. Before the deadline initiation time the priority of a deadline job
+              will be raised  steadily  until  it
+              reaches the maximum as configured by the Grid Engine administrator.
+
+              This option is applicable only for users allowed to submit deadline jobs.
+
+              If  this  option  or  a  corresponding  value in qmon is specified then this
+              value will be passed to defined JSV
+              instances as parameter with the name dl. The format for the date_time value
+              is CCYYMMDDhhmm.SS (see -jsv  option
+              below or find more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-e',
+                                     metavar='path',
+                                     help="""\
+          -e [[hostname]:]path,...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines  or  redefines the path used for the standard error stream of the job.
+              For qsh, qrsh and qlogin only the
+              standard error stream of prolog and epilog is redirected.  If the path
+              constitutes an absolute  path  name,  the
+              error-path  attribute  of  the  job  is  set to path, including the hostname.
+              If the path name is relative, Grid
+              Engine expands path either with the current working directory path
+              (if the -cwd switch (see above) is also spec‐
+              ified)  or with the home directory path. If hostname is present,
+              the standard error stream will be placed in the
+              corresponding location only if the job runs on the specified host.
+              If the path contains a ":"  without  a  host‐
+              name, a leading ":" has to be specified.
+
+              By  default  the  file name for interactive jobs is /dev/null.
+              For batch jobs the default file name has the form
+              job_name.ejob_id and job_name.ejob_id.task_id for array job tasks (see -t option
+              below).
+
+              If path is a directory, the standard error stream of the job will be put
+              in this  directory  under  the  default
+              file  name.  If the pathname contains certain pseudo environment variables,
+              their value will be expanded at run‐
+              time of the job and will be used to constitute the standard error stream path name.
+              The following  pseudo  envi‐
+              ronment variables are supported currently:
+
+              $HOME       home directory on execution machine
+              $USER       user ID of job owner
+              $JOB_ID     current job ID
+              $JOB_NAME   current job name (see -N option)
+              $HOSTNAME   name of the execution host
+              $TASK_ID    array job task index number
+
+              Alternatively  to  $HOME  the tilde sign "~" can be used as common in csh(1)
+              or ksh(1).  Note, that the "~" sign
+              also works in combination with user names, so that "~<user>" expands to the
+              home  directory  of  <user>.  Using
+              another user ID than that of the job owner requires corresponding permissions,
+              of course.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified then this value
+              will  be  passed  to  defined  JSV
+              instances  as  parameter  with  the  name  e.  (see -jsv option below or
+              find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-hard',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Signifies that all -q and -l resource requirements following in the command
+              line will be hard  requirements  and
+              must be satisfied in full before a job can be scheduled.
+              As Grid Engine scans the command line and script file for Grid Engine options
+              and parameters it builds a list of
+              resources required by a job. All such resource requests are considered as
+              absolutely essential for  the  job  to
+              commence. If the -soft option (see below) is encountered during the scan then
+              all following resources are desig‐
+              nated as "soft requirements" for execution, or "nice-to-have, but not essential".
+              If the -hard flag  is  encoun‐
+              tered  at a later stage of the scan, all resource requests following it once again
+              become "essential". The -hard
+              and -soft options in effect act as "toggles" during the scan.
+
+              If this option or a corresponding value in qmon is specified then the corresponding
+              -q and -l resource  require‐
+              ments  will  be passed to defined JSV instances as parameter with the names
+              q_hard and l_hard. Find for informa‐
+              tion in the sections describing -q and -l.  (see -jsv option below or find
+              more information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qalter', 'qresub']:
+            # NOTE in SGE this is -h, here I have renamed it to -hold
+            # TODO check if multiple holds are parsed correctly
+            self.parser.add_argument('-hold',
+                                     choices='usonUOS',
+                                     help="""\
+              NOTE: Originally defined as -h, but changed to -hold here.
+
+              Available for qsub (only -h), qrsh, qalter and qresub (hold state is
+              removed when not set explicitly).
+
+              List of holds to place on a job, a task or some tasks of a job.
+
+              `u'  denotes a user hold.
+              `s'  denotes a system hold.
+              `o'  denotes a operator hold.
+              `n'  denotes no hold (requires manager privileges).
+
+              As  long  as  any hold other than `n' is assigned to the job the job is
+              not eligible for execution. Holds can be
+              released via qalter and qrls(1).  In case of qalter this is supported
+              by the following additional option  speci‐
+              fiers for the -h switch:
+
+              `U'  removes a user hold.
+              `S'  removes a system hold.
+              `O'  removes a operator hold.
+
+              Grid  Engine managers can assign and remove all hold types,
+              Grid Engine operators can assign and remove user and
+              operator holds, and users can only assign or remove user holds.
+
+              In the case of qsub only user holds can be placed on a job and thus
+              only the first form of the option  with  the
+              -h switch alone is allowed.  As opposed to this, qalter requires
+              the second form described above.
+
+              An alternate means to assign hold is provided by the qhold(1) facility.
+
+              If the job is a array job (see the -t option below), all tasks specified via
+              -t are affected by the -h operation
+              simultaneously.
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job, however.
+
+              If  this  option  is specified with qsub or during the submission
+              of a job in qmon then the parameter h with the
+              value u will be passed to the defined JSV instances indicating that
+              the job will be in user hold after the  sub‐
+              mission finishes.  (see -jsv option below or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qalter']:
+            self.parser.add_argument('-hold_jid',
+                                     nargs='+',
+                                     metavar='wc_job_list',
+                                     help="""\
+              Available for qsub, qrsh, and qalter only. See sge_types(1).
+              for wc_job_list definition.
+
+              Defines  or  redefines  the job dependency list of the submitted job.
+              A reference by job name or pattern is only
+              accepted if the referenced job is owned by the same user as the referring job.
+              The submitted job is not eligible
+              for  execution unless all jobs referenced in the comma-separated job id and/or
+              job name list have completed.  If
+              any of the referenced jobs exits with exit code 100, the submitted
+              job will remain ineligible for execution.
+
+              With the help of job names or regular pattern one can specify a job
+              dependency on multiple jobs  satisfying  the
+              regular  pattern  or  on all jobs with the requested name.
+              The name dependencies are resolved at submit time and
+              can only be changed via qalter. New jobs or name changes
+              of other jobs will not be taken into account.
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job, however.
+
+              If  this  option  or  a  corresponding  value in qmon is specified
+              then this value will be passed to defined JSV
+              instances as parameter with the name hold_jid.
+              (see -jsv option below or find more information  concerning  JSV
+              in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qalter']:
+            self.parser.add_argument('-hold_jid_ad',
+                                     nargs='+',
+                                     metavar='wc_job_list',
+                                     help="""\
+              Available for qsub, qrsh, and qalter only. See sge_types(1).
+              for wc_job_list definition.
+
+              Defines  or  redefines the job array dependency list of
+              the submitted job. A reference by job name or pattern is
+              only accepted if the referenced job is owned by the same
+              user as the referring job. Each sub-task of the submit‐
+              ted  job  is  not eligible for execution unless the corresponding
+              sub-tasks of all jobs referenced in the comma-
+              separated job id and/or job name list have completed.
+              If any array task of the referenced jobs exits with  exit
+              code 100, the dependent tasks of the submitted job will remain
+              ineligible for execution.
+
+              With  the  help of job names or regular pattern one can specify
+              a job dependency on multiple jobs satisfying the
+              regular pattern or on all jobs with the requested name.
+              The name dependencies are resolved at  submit  time  and
+              can only be changed via qalter. New jobs or name changes of other
+              jobs will not be taken into account.
+
+              If  either  the submitted job or any job in wc_job_list are
+              not array jobs with the same range of sub-tasks (see
+              -t option below), the request list will be rejected and the
+              job create or modify operation will error.
+
+              qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job, however.
+
+              If  this  option  or  a  corresponding  value in qmon is
+              specified then this value will be passed to defined JSV
+              instances as parameter with the name hold_jid_ad.
+              (see -jsv option below or find  more  information  concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-i',
+                                     metavar='file',
+                                     help="""\
+       -i [[hostname]:]file,...
+              Available for qsub, and qalter only.
+
+              Defines or redefines the file used for the standard input stream of
+              the job. If the file constitutes an absolute
+              filename, the input-path attribute of the job is set to path,
+              including the hostname. If the path name is  rela‐
+              tive, Grid Engine expands path either with the current working
+              directory path (if the -cwd switch (see above) is
+              also specified) or with the home directory path. If hostname is present,
+              the  standard  input  stream  will  be
+              placed  in  the  corresponding  location  only if the job runs
+              on the specified host. If the path contains a ":"
+              without a hostname, a leading ":" has to be specified.
+
+              By default /dev/null is the input stream for the job.
+
+              It is possible to use certain pseudo variables, whose values
+              will be expanded at runtime of the job and will  be
+              used to express the standard input stream as described in
+              the -e option for the standard error stream.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified then
+              this value  will  be  passed  to  defined  JSV
+              instances  as  parameter  with  the  name  i.
+              (see -jsv option below or find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qrsh', 'qmake']:
+            self.parser.add_argument('-inherit',
+                                     action='store_true',
+                                     help="""\
+              Available only for qrsh and qmake(1).
+
+              qrsh allows the user to start a task in an already scheduled parallel job.
+              The option -inherit  tells  qrsh  to
+              read a job id from the environment variable JOB_ID and start the
+              specified command as a task in this job. Please
+              note that in this case, the hostname of the host where the command
+              will be executed must precede the command  to
+              execute; the syntax changes to
+
+              qrsh -inherit [ other options ] hostname command [ command_args ]
+
+              Note also, that in combination with -inherit, most other command line
+              options will be ignored.  Only the options
+              -verbose, -v and -V will be interpreted.  As a replacement to option
+              -cwd please use -v PWD.
+
+              Usually a task should have the same environment (including the
+              current working directory) as  the  corresponding
+              job, so specifying the option -V should be suitable for most applications.
+
+              Note:  If  in  your  system  the qmaster tcp port is not configured as a service,
+              but rather via the environment
+              variable GE_QMASTER_PORT, make sure that this variable is set in the
+              environment when calling qrsh or qmake with
+              the  -inherit  option.  If  you  call  qrsh  or  qmake with the
+              -inherit option from within a job script, export
+              GE_QMASTER_PORT with the option "-v GE_QMASTER_PORT" either as
+              a command argument or an embedded directive.
+
+              This parameter is not available in the JSV context.
+              (see -jsv option below or find more information  concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-j',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Specifies whether or not the standard error stream of the job
+              is merged into the standard output stream.
+              If both the -j y and the -e options are present,
+              Grid Engine sets but ignores the error-path attribute.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+
+              The value specified with this option or the corresponding
+              value specified in qmon will only be passed to defined
+              JSV instances if the value is yes.  The name of the parameter will be j.
+              The value will be y also when then long
+              form yes was specified during submission.
+              (see -jsv option below or find more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-js',
+                                     nargs='?',
+                                     type=int,
+                                     metavar='job_share',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines  or  redefines the job share of the job relative to other jobs.
+              Job share is an unsigned integer value.
+              The default job share value for jobs is 0.
+
+              The job share influences the Share Tree Policy and the Functional Policy.
+              It has no effect on  the  Urgency  and
+              Override  Policies  (see  share_tree(5), sched_conf(5) and the
+              Grid Engine Installation and Administration Guide
+              for further information on the resource management policies supported
+              by Grid Engine).
+
+              In case of the Share Tree Policy, users can distribute the tickets to
+              which they are  currently  entitled  among
+              their  jobs  using different shares assigned via -js.
+              If all jobs have the same job share value, the tickets are
+              distributed evenly. Otherwise, jobs receive tickets relative
+              to the different job shares. Job shares are treated
+              like an additional level in the share tree in the latter case.
+
+              In  connection  with  the  Functional Policy, the job share can be
+              used to weight jobs within the functional job
+              category.  Tickets are distributed relative to any uneven
+              job share distribution treated as a virtual share dis‐
+              tribution level underneath the functional job category.
+
+              If  both  the  Share Tree and the Functional Policy are active,
+              the job shares will have an effect in both poli‐
+              cies, and the tickets independently derived in each of them are
+              added to the total number of  tickets  for  each
+              job.
+
+              If  this  option  or  a  corresponding  value in qmon is specified
+              then this value will be passed to defined JSV
+              instances as parameter with the name js.  (see -jsv option below or
+              find  more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']:
+            self.parser.add_argument('-jsv',
+                                     metavar='jsv_url',
+                                     help="""\
+              Available for qsub, qsh, qrsh and qlogin only.
+
+              Defines  a  client JSV instance which will be executed to
+              verify the job specification before the job is sent to
+              qmaster.
+
+              In contrast to other options this switch will not be overwritten
+              if  it  is  also  used  in  sge_request  files.
+              Instead all specified JSV instances will be executed to verify
+              the job to be submitted.
+
+              The  JSV  instance  which is directly passed with the commandline
+              of a client is executed as first to verify the
+              job specification. After that the JSV instance which might have
+              been defined in various sge_request  files  will
+              be triggered to check the job. Find more details
+              in man page jsv(1) and sge_request(5).
+
+              The syntax of the jsv_url is specified in sge_types(1).()""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-l',
+                                     metavar='keywords',
+                                     help="""\
+       -l resource=value,...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Launch  the  job in a Grid Engine queue meeting the given resource
+              request list.  In case of qalter the previous
+              definition is replaced by the specified one.
+
+              complex(5) describes how a list of available resources and  their
+              associated  valid  value  specifiers  can  be
+              obtained.
+
+              There  may  be  multiple -l switches in a single command.
+              You may request multiple -l options to be soft or hard
+              both in the same command line. In case of a serial job multiple
+              -l switches refine the definition for the sought
+              queue.
+
+              Qalter  allows  changing the value of this option even while the
+              job is running, but only if the initial list of
+              resources does not contain a resource that is marked as consumable.
+              However the modification will only be effec‐
+              tive after a restart or migration of the job.
+
+              If  this option or a corresponding value in qmon is specified the
+              these hard and soft resource requirements will
+              be passed to defined JSV instances as parameter with the names
+              l_hard and l_soft. If regular expressions will be
+              used  for  resource requests, then these expressions will
+              be passed as they are. Also shortcut names will not be
+              expanded.  (see -jsv option above or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            # TODO check if multiple arguments are parsed correctly
+            self.parser.add_argument('-m',
+                                     nargs='+',
+                                     choices='beasn',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines or redefines under which circumstances mail
+              is to be sent to the job owner or to the users defined  with
+              the -M option described below. The option arguments
+              have the following meaning:
+
+              `b'     Mail is sent at the beginning of the job.
+              `e'     Mail is sent at the end of the job.
+              `a'     Mail is sent when the job is aborted or
+                      rescheduled.
+              `s'     Mail is sent when the job is suspended.
+              `n'     No mail is sent.
+
+              Currently no mail is sent when a job is suspended.
+
+              Qalter  allows  changing the b, e, and a option arguments
+              even while the job executes. The modification of the b
+              option argument will only be in effect after a restart
+              or migration of the job, however.
+
+              If this option or a corresponding value in qmon is
+              specified then this value  will  be  passed  to  defined  JSV
+              instances as parameter with the name m.  (see -jsv option
+              above or find more information concerning JSV in""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-M',
+                                     metavar='user[@host]',
+                                     help="""\
+       -M user[@host],...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines or redefines the list of users to which the server
+              that executes the job has to send mail, if the server
+              sends mail about the job.  Default is the job owner at the originating host.
+
+              Qalter allows changing this option even while the job executes.
+
+              If this option or a corresponding value in qmon is specified then
+              this value  will  be  passed  to  defined  JSV
+              instances  as  parameter  with  the  name  M.  (see -jsv option above or
+              find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-masterq',
+                                     nargs='+',
+                                     metavar='wc_queue_list',
+                                     help="""\
+              Available for qsub, qrsh, qsh, qlogin and qalter.  Only meaningful
+              for parallel jobs, i.e. together with the -pe option.
+
+              Defines or redefines a list of cluster queues, queue domains and
+              queue instances which may be used to become the
+              so called master queue of this parallel job. A more detailed
+              description  of  wc_queue_list  can  be  found  in
+              sge_types(1).   The  master queue is defined as the queue where
+              the parallel job is started. The other queues to
+              which the parallel job spawns tasks are called slave queues.
+              A parallel job only has one master queue.
+
+              This parameter has all the properties of a resource request
+              and will be merged with  requirements  derived  from
+              the -l option described above.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified
+              the this hard resource requirement will  be  passed
+              to  defined  JSV  instances as parameter with the name masterq.
+              (see -jsv option above or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qalter']:
+            self.parser.add_argument('-notify',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qrsh (with command) and qalter only.
+
+              This flag, when set causes Grid Engine to send "warning" signals
+              to a running job prior to sending  the  signals
+              themselves.  If  a  SIGSTOP  is pending, the job will receive
+              a SIGUSR1 several seconds before the SIGSTOP. If a
+              SIGKILL is pending, the job will receive a SIGUSR2 several
+              seconds before the SIGKILL.  This option provides the
+              running  job, before receiving the SIGSTOP or SIGKILL,
+              a configured time interval to do e.g. cleanup operations.
+              The amount of time delay is controlled by the notify parameter
+              in each queue configuration (see queue_conf(5)).
+
+              Note that the Linux operating system "misused" the user
+              signals SIGUSR1 and SIGUSR2 in some early  Posix  thread
+              implementations.  You might not want to use the
+              -notify option if you are running multi-threaded applications in
+              your jobs under Linux, particularly on 2.0 or earlier kernels.
+
+              Qalter allows changing this option even while the job executes.
+
+              Only if this option is used the parameter named notify with
+              the value y will be passed to defined JSV instances.
+              (see -jsv option above or find more information concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']:
+            self.parser.add_argument('-now',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub, qsh, qlogin and qrsh.
+
+              -now y tries to start the job immediately or not at all.
+              The command returns 0 on success, or 1 on failure (also
+              if the job could not be scheduled immediately).
+              For array jobs submitted with the -now  option,  if  all  tasks
+              cannot be immediately scheduled, no tasks are scheduled.
+              -now y is default for qsh, qlogin and qrsh
+
+              With  the -now n option, the job will be put into the pending
+              queue if it cannot be executed immediately. -now n
+              is default for qsub.
+
+              The value specified with this option or the corresponding
+              value specified in qmon will only be passed to defined
+              JSV  instances  if  the value is yes.  The name of the
+              parameter will be now. The value will be y also when then
+              long form yes was specified during submission.
+              (see -jsv option above or find more information  concerning  JSV
+              in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-N',
+                                     metavar='name',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              The  name  of  the job. The name should follow the "name"
+              definition in sge_types(1).  Invalid job names will be
+              denied at submit time.
+
+              If the -N option is not present, Grid Engine assigns
+              the name of the job script to the job after  any  directory
+              pathname has been removed from the script-name.
+              If the script is read from standard input, the job name defaults
+              to STDIN.
+
+              In the case of qsh or qlogin with the -N option is absent,
+
+              the string `INTERACT' is assigned to the job.
+
+              In the case of qrsh if the -N option is absent, the resulting
+              job name is determined from the qrsh command  line
+              by  using the argument string up to the first
+              occurrence of a semicolon or whitespace and removing the directory
+              pathname.
+
+              Qalter allows changing this option even while the job executes.
+
+              The value specified with this option or the corresponding value
+              specified in qmon will be passed to defined  JSV
+              instances  as  parameter  with  the  name  N.  (see -jsv
+              option above or find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qrsh']:
+            self.parser.add_argument('-noshell',
+                                     action='store_true',
+                                     help="""\
+              Available only for qrsh with a command line.
+
+              Do not start the command line given to qrsh in a user's login shell,
+              i.e.   execute  it  without  the  wrapping
+              shell.
+
+              This  option  can  be used to speed up execution as some overhead,
+              like the shell startup and sourcing the shell
+              resource files, is avoided.
+
+              This option can only be used if no shell-specific command line
+              parsing is required. If the command line contains
+              shell  syntax  like environment variable substitution or (back) quoting,
+              a shell must be started.  In this case,
+              either do not use the -noshell option or include the shell call in the command line.
+
+              Example:
+              qrsh echo '$HOSTNAME'
+              Alternative call with the -noshell option
+              qrsh -noshell /bin/tcsh -f -c 'echo $HOSTNAME'""")
+
+        if prog in ['qrsh']:
+            self.parser.add_argument('-nostdin',
+                                     action='store_true',
+                                     help="""\
+              Available only for qrsh.
+
+              Suppress the input stream STDIN - qrsh will pass the option -n
+              to the rsh(1) command. This is especially useful,
+              if  multiple tasks are executed in parallel using qrsh, e.g.
+              in a make(1) process - it would be undefined, which
+              process would get the input.""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-o',
+                                     metavar='path',
+                                     help="""\
+       -o [[hostname]:]path,...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              The path used for the standard output stream of the job.
+              The path is handled as described in the -e  option  for
+              the standard error stream.
+
+              By  default  the  file  name  for standard output has the
+              form job_name.ojob_id and job_name.ojob_id.task_id for
+              array job tasks (see -t option below).
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after a restart or migration of the job, however.
+
+              If  this  option  or  a  corresponding  value in qmon is
+              specified then this value will be passed to defined JSV
+              instances as parameter with the name o.  (see -jsv option
+              above or  find  more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qalter']:
+            self.parser.add_argument('-ot',
+                                     metavar='override_tickets',
+                                     help="""\
+              Available for qalter only.
+
+              Changes the number of override tickets for the specified job.
+              Requires manager/operator privileges.""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-P',
+                                     metavar='project_name',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Specifies  the  project  to which this job is assigned.
+              The administrator needs to give permission to individual
+              users to submit jobs to a specific project. (see -aprj option to qconf(1)).
+
+              If this option or a corresponding value in qmon is specified then
+              this value  will  be  passed  to  defined  JSV
+              instances  as  parameter  with  the  name ot.  (see -jsv option
+              above or find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-p',
+                                     metavar='priority',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines or redefines the priority of the job relative to other jobs.
+              Priority is an integer in the range  -1023
+              to 1024.  The default priority value for jobs is 0.
+
+              Users  may  only decrease the priority of their jobs.
+              Grid Engine managers and administrators may also increase
+              the priority associated with jobs. If a pending job has higher priority,
+              it is earlier eligible for  being  dis‐
+              patched by the Grid Engine scheduler.
+
+              If  this  option or a corresponding value in qmon is specified and
+              the priority is not 0 then this value will be
+              passed to defined JSV instances as parameter with the name p.
+              (see -jsv option above or find  more  information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-slot',
+                                     metavar='slot',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Defines or redefines the priority of the job relative to other jobs.
+              Priority is an integer in the range  -1023
+              to 1024.  The default priority value for jobs is 0.
+
+              Users  may  only decrease the priority of their jobs.
+              Grid Engine managers and administrators may also increase
+              the priority associated with jobs. If a pending job has higher priority,
+              it is earlier eligible for  being  dis‐
+              patched by the Grid Engine scheduler.
+
+              If  this  option or a corresponding value in qmon is specified and
+              the priority is not 0 then this value will be
+              passed to defined JSV instances as parameter with the name p.
+              (see -jsv option above or find  more  information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-pe',
+                                     nargs=2,
+                                     metavar=('parallel_environment', 'n'),
+                                     help="""\
+       -pe parallel_environment n[-[m]]|[-]m,...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Parallel programming environment (PE) to instantiate.
+              For more detail about PEs, please see the sge_types(1).
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified
+              then the parameters pe_name, pe_min and pe_max will
+              be  passed to configured JSV instances where pe_name will be the
+              name of the parallel environment and the values
+              pe_min and pe_max represent the values n and m which have been
+              provided with the -pe option. A missing  specifi‐
+              cation  of  m  will be expanded as value 9999999 in JSV scripts
+              and it represents the value infinity.  (see -jsv
+              option above or find more information concerning JSV in jsv(1))"""
+                                     )
+
+        if prog in ['qrsh', 'qlogin']:
+            self.parser.add_argument('-pty',
+                                     choices=yesno,
+                                     help="""\
+              Available for qrsh and qlogin only.
+
+              -pty yes enforces the job to be started in a pseudo terminal (pty).
+              If no pty is available, the job start fails.
+              -pty  no  enforces the job to be started without a pty.
+              By default, qrsh without a command and qlogin start the
+              job in a pty, qrsh with a command starts the job without a pty.
+
+              This parameter is not available in the JSV context.
+              (see -jsv option above or find more information  concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-q',
+                                     nargs='+',
+                                     metavar='wc_queue_list',
+                                     help="""\
+              Available for qsub, qrsh, qsh, qlogin and qalter.
+
+              Defines  or  redefines  a  list of cluster queues,
+              queue domains or queue instances which may be used to execute
+              this job. Please find a description of wc_queue_list in sge_types(1).
+              This parameter has all the properties  of
+              a resource request and will be merged with requirements derived from the
+              -l option described above.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              If this option or a corresponding value in qmon is specified
+              the these hard and soft resource requirements  will
+              be  passed  to defined JSV instances as parameters with the
+              names q_hard and q_soft. If regular expressions will
+              be used for resource requests, then these expressions will
+              be passed as they are. Also shortcut names  will  not
+              be expanded.  (see -jsv option above or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-R',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub, qrsh, qsh, qlogin and qalter.
+
+              Indicates  whether a reservation for this job should be done.
+              Reservation is never done for immediate jobs, i.e.
+              jobs submitted using the -now yes option.  Please note that
+              regardless of the reservation request, job  reserva‐
+              tion  might  be disabled using max_reservation in sched_conf(5)
+              and might be limited only to a certain number of
+              high priority jobs.
+
+              By default jobs are submitted with the -R n option.
+
+              The value specified with this option or the corresponding value
+              specified in qmon will only be passed to defined
+              JSV instances if the value is yes.  The name of the parameter will be R.
+              The value will be y also when then long
+              form yes was specified during submission.
+              (see -jsv option above or find more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-r',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub and qalter only.
+
+              Identifies  the  ability of a job to be rerun or not.
+              If the value of -r is 'yes', the job will be rerun if the
+              job was aborted without leaving a consistent exit state.
+              (This is typically the case if the node on  which  the
+              job is running crashes).  If -r is 'no',
+              the job will not be rerun under any circumstances.
+              Interactive jobs submitted with qsh, qrsh or qlogin are not rerunnable.
+
+              Qalter allows changing this option even while the job executes.
+
+              The value specified with this option or the corresponding value specified
+              in qmon will only be passed to defined
+              JSV instances if the value is yes.  The name of the parameter will be r.
+              The value will be y also when then long
+              form  yes  was  specified  during submission.  (see -jsv option above or
+              find more information concerning JSV in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-sc',
+                                     action='append',
+                                     metavar='variable[=value]',
+                                     help="""\
+       -sc variable[=value],...
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Sets the given name/value pairs as the job's context. Value may be omitted.
+              Grid Engine replaces the job's  pre‐
+              viously  defined  context  with the one given as the argument.
+              Multiple -ac, -dc, and -sc options may be given.
+              The order is important.
+
+              Contexts provide a way to dynamically attach and remove meta-information
+              to and from a job.  The  context  vari‐
+              ables are not passed to the job's execution context in its environment.
+
+              Qalter allows changing this option even while the job executes.
+
+              The  outcome  of  the  evaluation  of all -ac, -dc, and -sc options
+              or corresponding values in qmon is passed to
+              defined JSV instances as parameter with the name ac.
+              (see -jsv option above or find more information concerning
+              JSV in jsv(1))""")
+
+        if prog in ['qsub']:
+            self.parser.add_argument('-shell',
+                                     choices=yesno,
+                                     help="""\
+              Available only for qsub.
+
+              -shell  n causes qsub to execute the command line directly,
+              as if by exec(2).  No command shell will be executed
+              for the job.  This option only applies when -b y is also used.
+              Without -b y, -shell n has no effect.
+
+              This option can be used to speed up execution as some overhead,
+              like the shell startup and  sourcing  the  shell
+              resource files is avoided.
+
+              This option can only be used if no shell-specific command line parsing
+              is required. If the command line contains
+              shell syntax, like environment variable substitution or (back) quoting,
+              a shell must be started.  In  this  case
+              either  do  not  use  the -shell n option or execute the shell as the
+              command line and pass the path to the exe‐
+              cutable as a parameter.
+
+              If a job executed with the -shell n option fails due to a user error,
+              such as an invalid path to the executable,
+              the job will enter the error state.
+
+              -shell y cancels the effect of a previous -shell n.  Otherwise, it has no effect.
+
+              See -b and -noshell for more information.
+
+              The value specified with this option or the corresponding value
+              specified in qmon will only be passed to defined
+              JSV instances if the value is yes.  The name of the parameter
+              will be shell. The value will be y also when  then
+              long  form  yes was specified during submission.
+              (see -jsv option above or find more information concerning JSV
+              in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-soft',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter only.
+
+              Signifies that all resource requirements following in the command
+              line will be soft requirements and are  to  be
+              filled on an "as available" basis.
+              As  Grid  Engine scans the command line and script file for
+              Grid Engine options and parameters, it builds a list
+              of resources required by the job. All such resource requests are
+              considered as absolutely essential for the  job
+              to  commence.  If the -soft option is encountered during the
+              scan then all following resources are designated as
+              "soft requirements" for execution, or "nice-to-have, but not essential".
+              If  the  -hard  flag  (see  above)  is
+              encountered  at a later stage of the scan, all resource requests following
+              it once again become "essential". The
+              -hard and -soft options in effect act as "toggles" during the scan.
+
+              If this option or a corresponding value in qmon is
+              specified then the corresponding -q and -l resource  require‐
+              ments  will  be passed to defined JSV instances as parameter
+              with the names q_soft and l_soft. Find for informa‐
+              tion in the sections describing -q and -l.  (see -jsv option
+              above or find more information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub']:
+            self.parser.add_argument('-sync',
+                                     choices=yesno,
+                                     help="""\
+              Available for qsub.
+
+              -sync  y  causes qsub to wait for the job to complete before exiting.
+              If the job completes successfully, qsub's
+              exit code will be that of the completed job.
+              If the job fails to complete successfully, qsub will print  out  a
+              error  message indicating why the job failed and will have an exit code of 1.
+              If qsub is interrupted, e.g. with
+              CTRL-C, before the job completes, the job will be canceled.
+              With the -sync n option, qsub will exit with an exit code of 0 as soon as the
+              job  is  submitted  successfully.
+              -sync n is default for qsub.
+              If  -sync  y is used in conjunction with -now y, qsub will behave
+              as though only -now y were given until the job
+              has been successfully scheduled, after which time qsub will behave
+              as though only -sync y were given.
+              If -sync y is used in conjunction with -t n[-m[:i]], qsub will
+              wait for all the job's tasks to  complete  before
+              exiting.  If all the job's tasks complete successfully, qsub's
+              exit code will be that of the first completed job
+              tasks with a non-zero exit code, or 0 if all job tasks exited
+              with an exit code of 0.  If any of the job's tasks
+              fail  to  complete  successfully, qsub will print out an
+              error message indicating why the job task(s) failed and
+              will have an exit code of 1.  If qsub is interrupted,
+              e.g. with CTRL-C, before the job  completes,  all  of  the
+              job's tasks will be canceled.
+
+              Information  that  this  switch  was specified during
+              submission is not available in the JSV context.  (see -jsv
+              option above or find more information concerning JSV in jsv(1))"""
+                                     )
+
+        if prog in ['qsub', 'qsh', 'qalter']:
+            self.parser.add_argument('-S',
+                                     metavar='pathname',
+                                     help="""\
+       -S [[hostname]:]pathname,...
+              Available for qsub, qsh and qalter.
+
+              Specifies the interpreting shell for the job.
+              Only one pathname component without a host specifier is valid  and
+              only  one path name for a given host is allowed.
+              Shell paths with host assignments define the interpreting shell
+              for the job if the host is the execution host.
+              The shell path without host specification is used if  the  execu‐
+              tion host matches none of the hosts in the list.
+
+              Furthermore,  the  pathname  can be constructed with pseudo
+              environment variables as described for the -e option
+              above.
+
+              In the case of qsh the specified shell path is used to
+              execute the  corresponding  command  interpreter  in  the
+              xterm(1)  (via its -e option) started on behalf of the interactive job.
+              Qalter allows changing this option even
+              while the job executes. The modified parameter will only be in effect
+              after a restart or migration of  the  job,
+              however.
+
+              If  this  option  or  a  corresponding  value in qmon is
+              specified then this value will be passed to defined JSV
+              instances as parameter with the name S.  (see -jsv option
+              above or  find  more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if True or prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-t',
+                                     metavar='n[-m[:s]]',
+                                     help="""\
+              Available for qsub and qalter only.
+
+              Submits a so called Array Job, i.e. an array of identical
+              tasks being differentiated only by an index number and
+              being treated by Grid Engine almost like a series of jobs.
+              The option argument to -t  specifies  the  number  of
+              array job tasks and the index number which will be associated with the tasks.
+              The index numbers will be exported
+              to the job tasks via the environment variable GE_TASK_ID.
+              The option arguments n, m  and  s  will  be  available
+              through the environment variables GE_TASK_FIRST,
+              GE_TASK_LAST and  GE_TASK_STEPSIZE.
+
+              Following restrictions apply to the values n and m:
+
+                     1 <= n <= MIN(2^31-1, max_aj_tasks)
+                     1 <= m <= MIN(2^31-1, max_aj_tasks)
+                     n <= m
+
+              max_aj_tasks is defined in the cluster configuration (see sge_conf(5))
+
+              The  task  id range specified in the option argument may be a single
+              number, a simple range of the form n-m or a
+              range with a step size. Hence, the task id range specified by
+              2-10:2 would result in the task id indexes  2,  4,
+              6,  8, and 10, for a total of 5 identical tasks, each with
+              the environment variable GE_TASK_ID containing one of
+              the 5 index numbers.
+
+              All array job tasks inherit the same resource requests and
+              attribute definitions as specified  in  the  qsub  or
+              qalter  command  line,  except  for  the  -t  option.
+              The tasks are scheduled independently and, provided enough
+              resources exist, concurrently, very much like separate jobs.
+              However, an array job or a sub-array there of  can
+              be  accessed  as a single unit by commands like qmod(1) or qdel(1).
+              See the corresponding manual pages for fur‐
+              ther detail.
+
+              Array jobs are commonly used to execute the same type of operation
+              on varying input data  sets  correlated  with
+              the task index number. The number of tasks in a array job is unlimited.
+
+              STDOUT and STDERR of array job tasks will be written into different
+              files with the default location
+
+              <jobname>.['e'|'o']<job_id>'.'<task_id>
+
+              In order to change this default, the -e and -o options (see above)
+              can be used together with the pseudo environ‐
+              ment variables $HOME, $USER, $JOB_ID, $JOB_NAME, $HOSTNAME, and $GE_TASK_ID.
+
+              Note, that you can use the output redirection to divert the output
+              of all tasks into  the  same  file,  but  the
+              result of this is undefined.
+
+              If  this  option  or  a  corresponding  value in qmon is specified
+              then this value will be passed to defined JSV
+              instances as parameters with the name t_min, t_max and t_step
+              (see -jsv option above or  find  more  information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qalter']:
+            self.parser.add_argument('-tc',
+                                     type=int,
+                                     metavar='max_running_tasks',
+                                     help="""\
+              -allow  users to limit concurrent array job task
+              execution. Parameter max_running_tasks specifies maximum number
+              of simultaneously running tasks.  For example we have
+              running SGE with 10 free slots. We call qsub -t 1-100  -tc
+              2 jobscript. Then only 2 tasks will be scheduled to run even
+              when 8 slots are free.""")
+
+        if prog in ['qsub']:
+            self.parser.add_argument('-terse',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub only.
+
+              -terse  causes  the qsub to display only the job-id of the
+              job being submitted rather than the regular "Your job
+              ..." string.  In case of an error the error is reported on stderr as usual.
+              This can be helpful for scripts which need to parse qsub output to get the job-id.
+
+              Information that this switch was specified during submission
+              is not available in the  JSV  context.   (see  -jsv
+              option above or find more information concerning JSV in jsv(1))"""
+                                     )
+
+        if prog in ['qalter']:
+            self.parser.add_argument('-u',
+                                     metavar='username',
+                                     help="""\
+       -u username,...
+              Available  for  qalter  only. Changes are only made
+              on those jobs which were submitted by users specified in the
+              list of usernames.  For managers it is possible to use
+              the qalter -u '*' command  to  modify  all  jobs  of  all
+              users.
+
+              If you use the -u switch it is not permitted to
+              specify an additional wc_job_range_list.""")
+
+        if prog in ['qsub', 'qrsh', 'qalter']:
+            self.parser.add_argument('-v',
+                                     metavar='variable[=value]',
+                                     help="""\
+       -v variable[=value],...
+              Available for qsub, qrsh (with command argument) and qalter.
+
+              Defines  or  redefines  the environment
+              variables to be exported to the execution context of the job.  If the -v
+              option is present Grid Engine will add the
+              environment variables defined as arguments to the switch and, option‐
+              ally, values of specified variables, to the execution context of the job.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              All environment variables specified with -v, -V or the
+              DISPLAY variable provided with -display will be  exported
+              to the defined JSV instances only optionally when this is
+              requested explicitly during the job submission verifi‐
+              cation.  (see -jsv option above or find more information concerning JSV in jsv(1))"""
+                                     )
+
+        if prog in ['qrsh', 'qmake']:
+            self.parser.add_argument('-verbose',
+                                     action='store_true',
+                                     help="""\
+              Available only for qrsh and qmake(1).
+
+              Unlike qsh and qlogin, qrsh does not output any
+              informational messages while establishing the session, compliant
+              with  the  standard rsh(1) and rlogin(1) system calls.
+              If the option -verbose is set, qrsh behaves like the qsh
+              and qlogin commands, printing information about the
+              process of establishing the rsh(1) or rlogin(1) session.""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-verify',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter.
+
+              Instead of submitting a job, prints detailed information
+              about the would-be job as though qstat(1) -j were used,
+              including the effects of command-line parameters and
+              the external environment.""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            # TODO parse acceptability of qrsh argument properly
+            self.parser.add_argument('-V',
+                                     action='store_true',
+                                     help="""\
+              Available for qsub, qsh, qrsh with command and qalter.
+
+              Specifies that all environment variables active within
+              the qsub utility be exported to the context of the job.
+
+              All  environment variables specified with -v, -V or the DISPLAY
+              variable provided with -display will be exported
+              to the defined JSV instances only optionally when this is
+              requested explicitly during the job submission verifi‐
+              cation.  (see -jsv option above or find more information
+              concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']:
+            self.parser.add_argument('-w',
+                                     choices='ewnpv',
+                                     help="""\
+              Available for qsub, qsh, qrsh, qlogin and qalter.
+
+              Specifies  a validation level applied to the job to be submitted
+              (qsub, qlogin, and qsh) or the specified queued
+              job (qalter).  The information displayed indicates whether the
+              job can possibly be scheduled assuming  an  empty
+              system  with no other jobs. Resource requests exceeding the
+              configured maximal thresholds or requesting unavail‐
+              able resource attributes are possible causes for jobs to fail this validation.
+
+              The specifiers e, w, n and v define the following validation modes:
+
+              `e'  error - jobs with invalid requests will be
+                   rejected.
+              `w'  warning - only a warning will be displayed
+                   for invalid requests.
+              `n'  none - switches off validation; the default for
+                   qsub, qalter, qrsh, qsh
+                   and qlogin.
+              `p'  poke - does not submit the job but prints a
+                   validation report based on a cluster as is with
+                   all resource utilizations in place.
+              `v'  verify - does not submit the job but prints a
+                   validation report based on an empty cluster.
+
+              Note, that the necessary checks are performance consuming
+              and hence the checking is switched off by default.  It
+              should also be noted that load values are not taken
+              into account with the verification since they are assumed to
+              be too volatile. To cause -w e verification to be passed
+              at submission time, it  is  possible  to  specify  non-
+              volatile values (non-consumables) or maximum values
+              (consumables) in complex_values.""")
+
+        if prog in ['qsub', 'qrsh', 'qsh', 'qalter']:
+            self.parser.add_argument('-wd',
+                                     metavar='working_dir',
+                                     help="""\
+              Available for qsub, qsh, qrsh and qalter only.
+
+              Execute  the  job  from  the  directory  specified in working_dir.
+              This switch will activate Grid Engine's path
+              aliasing facility, if the corresponding configuration files are present
+              (see ge_aliases(5)).
+
+              Qalter allows changing this option even while the job executes.
+              The modified parameter will only  be  in  effect
+              after  a  restart  or  migration  of  the  job,  however.
+              The parameter value will be available in defined JSV
+              instances as parameter with the name cwd (see -cwd switch above or
+              find  more  information  concerning  JSV  in
+              jsv(1))""")
+
+        if prog in ['qsub', 'qrsh']:
+            self.parser.add_argument('command',
+                                     help="""\
+              Available for qsub and qrsh only.
+
+              The job's scriptfile or binary.  If not present or if the operand
+              is the single-character string '-', qsub reads
+              the script from standard input.
+
+              The command will be available in defined JSV instances as parameter
+              with the name CMDNAME (see -jsv option above
+              or find more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsub', 'qrsh', 'qalter']:
+            self.parser.add_argument('command_args',
+                                     nargs='*',
+                                     help="""\
+              Available for qsub, qrsh and qalter only.
+
+              Arguments to the job. Not valid if the script is entered from standard input.
+
+              Qalter  allows  changing  this option even while the job executes.
+              The modified parameter will only be in effect
+              after a restart or migration of the job, however.
+
+              The number of command arguments is provided to configured
+              JSV instances as parameter with the name CMDARGS. Also
+              the  argument  values can by accessed. Argument names
+              have the format CMDARG<number> where <number> is a integer
+              between 0 and CMDARGS - 1.  (see -jsv option above or
+              find more information concerning JSV in jsv(1))""")
+
+        if prog in ['qsh']:
+            self.parser.add_argument('xterm_args',
+                                     nargs='*',
+                                     help="""\
+              Available for qsh only.
+
+              Arguments to the xterm(1) executable, as defined in the configuration.
+              For details, refer to ge_conf(5)).
+
+              Information concerning xterm_args will be available in JSV context as
+              parameters  with  the  name  CMDARGS  and
+              CMDARG<number>. Find more information above in section command_args.
+              (see -jsv option above or find more infor‐
+              mation concerning JSV in jsv(1))""")
+
+        # END SGE OPTION PARSER
+
+        # Initialize with defaults
+        self.parse('-cwd -V -j y -terse -pe lammpi 1 echo')
+
+    def parse(self, inputstring=''):
+        """Helper method: parses a string"""
+        return self.parse_args(inputstring.split())
+
+    def parse_args(self, args=None):
+        """Helper method: parses a list"""
+        if args is None:
+            self.args = self.parser.parse_args()  # default is sys.argv[1:]
+        else:
+            self.args = self.parser.parse_args(args)
+        return self.args
+
+    def write_qsub_script(self, filename, echo=False):
+        """
+        Writes the entire command line to a qsub script
+
+        filename: name of file to write
+        echo    : echo contents of script to stdout. Default: False
+        """
+
+        buf = ['#!/usr/bin/env qsub', '# Written using SGE module']
+
+        for option, value in self.args.__dict__.items():
+            if value is True:
+                value = ''
+
+            if option not in ['command', 'command_args', 'xterm_args']:
+                if isinstance(value, list):
+                    val = ' '.join(value)
+                else:
+                    val = str(value)
+
+                buf.append(' '.join(['#', '-' + option, val]))
+
+        args = getattr(self.args, 'command_args', [])
+        args = getattr(self.args, 'xterm_args', args)
+
+        buf.append(' '.join([self.args.command] + args))
+
+        if echo:
+            print('\n'.join(buf))
+
+        f = open(filename, 'w')
+        f.write('\n'.join(buf))
+        f.close()
+
+    def execute(self, mode='local', path=''):
+        """
+        Executes qsub
+
+        known modes: local - run locally
+                     echo  - echoes out execution string only
+
+        path: path to qsub/... executable: Default = nothing
+        """
+
+        # Form execution string
+
+        import os
+        program = os.path.join(path, self.prog)
+        options = []
+
+        for option, value in self.args.__dict__.items():
+            if value is True:
+                value = ''
+
+            if isinstance(value, list):
+                val = ' '.join(value)
+            else:
+                val = str(value)
+
+            if option not in ['command', 'command_args', 'xterm_args']:
+                options.append('-' + option + ' ' + val)
+
+        args = getattr(self.args, 'command_args', [])
+        args = getattr(self.args, 'xterm_args', args)
+
+        exestring = ' '.join([program] + options + [self.args.command] + args)
+        exestring = exestring.replace('-pe lammpi 1', '')
+        exestring = exestring.replace('-slot', '-pe make')
+        exestring = exestring.replace('-ll ', '-l ')
+        exestring = exestring.replace('-t 0', '')
+        #        exestring = exestring.replace('-j y','')
+
+        if mode == 'echo':
+            return (exestring)
+        elif mode == 'local':
+            import subprocess
+            p = subprocess.Popen(exestring,
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.STDOUT,
+                                 shell=True)
+            print(p.stdout.read())
+
+
+if __name__ == '__main__':
+    print('Attempting to validate qsub arguments using argparse')
+    o = qsubOptions()
+    o.parse_args()
+    o.args.t = '1-1000'
+    print('I will now print the script')
+    o.write_qsub_script('/dev/null', echo=True)
+    print('*' * 70)
+    print('I will now print the command line')
+    o.execute(mode='echo')