#! /usr/bin/env python3 from __future__ import print_function import os, re, string, sys, getopt, signal def version(): print ("Generic Colouriser 1.10.1") sys.exit() def help(): print("""Generic Colouriser 1.10.1 grc [options] command [args] Options: -e --stderr redirect stderr. If this option is selected, do not automatically redirect stdout -s --stdout redirect stdout, even if -e is selected -c name --config=name use name as configuration file for grcat --colour=word word is one of: on, off, auto --pty run command in pseudoterminal (experimental) """) sys.exit() def catch_signal(signum, frame): "catch signal sent to grc and forward it to the original application" global pidp # print('signal') try: os.kill(pidp, signum) except OSError: # if the subprocess already died pass try: optlist, args = getopt.getopt(sys.argv[1:], "sec:", ["stdout", "stderr", "config=", "colour=", "pty"] ) except: help() if not args: help() stdoutf = 0 stderrf = 0 # configure file for grcat cfile = "" colour = 1 use_pty = 0 for i in optlist: if i[0] in ["--stderr", "-e"]: # redirect stderr stderrf = 1 elif i[0] in ["--stdout", "-s"]: # redirect stdout stdoutf = 1 elif i[0] in ["--config", "-c"]: cfile = i[1] elif i[0] == "--colour": if i[1] == "on": colour = 1 elif i[1] == "off": colour = 0 elif i[1] == "auto": colour = sys.stdout.isatty() else: help() elif i[0] == '--pty': use_pty = 1 stdoutff = 1 stderrff = 0 if stderrf == 1: stdoutff = 0 stderrff = 1 if stdoutf == 1: stdoutff = 1 if use_pty: import pty conffile = None if cfile == "": home = os.environ.get('HOME') xdg = os.environ.get('XDG_CONFIG_HOME') if not xdg and home: xdg = home + '/.config' conffilenames = [] if xdg: conffilenames += [xdg + '/grc/grc.conf'] if home: conffilenames += [home + '/.grc/grc.conf'] conffilenames += ['/usr/local/etc/grc.conf', '/etc/grc.conf'] for i in conffilenames: # test if conffile exists, it can be also a pipe if os.path.exists(i) and not os.path.isdir(i): conffile = i break regexplist = [] if conffile: f = open(conffile, "r") while 1: l = f.readline() if l == "": break if l[0] == "#" or l[0] == '\012': continue regexp = l.strip() if re.search(regexp, ' '.join(args)): cfile = f.readline().strip() break signal.signal(signal.SIGINT, catch_signal) if cfile != "" and colour: if stdoutff: choo, chio = os.pipe() if stderrff: choe, chie = os.pipe() if use_pty: pidp, pty_fd = pty.fork() else: pidp = os.fork() if pidp == 0: # child, command to run if stdoutff: # connect child (this) stdout to pipe write end if not use_pty: os.dup2(chio, 1) os.close(choo) os.close(chio) if stderrff: os.dup2(chie, 2) os.close(choe) os.close(chie) os.execvp(args[0], args) if stdoutff: pido = os.fork() if pido == 0: # child, grcat # connect grcat's stdin to pipe read end, or pty master if use_pty: os.dup2(pty_fd, 0) else: os.dup2(choo, 0) os.close(choo) os.close(chio) if stderrff: os.close(choe) os.close(chie) os.execvp("grcat", ["grcat", cfile]) if stderrff: pide = os.fork() if pide == 0: # child os.dup2(choe, 0) os.dup2(2, 1) os.close(choe) os.close(chie) if stdoutff: os.close(choo) os.close(chio) os.execvp("grcat", ["grcat", cfile]) try: status = os.waitpid(pidp, 0)[1] except OSError: # interrupted system call status = None pass # this is probably not correct # except KeyboardInterrupt: # catching SIGINT does not work when using pty... # status = None # os.kill(pidp, signal.SIGINT) # pass if stderrff: os.close(chie) os.waitpid(pide, 0) os.close(choe) if stdoutff: os.close(chio) os.waitpid(pido, 0) os.close(choo) sys.exit(status and os.WEXITSTATUS(status)) else: pidp = os.fork() if pidp == 0: try: os.execvp(args[0], args) except FileNotFoundError: sys.stderr.write('grc: %s: command not found\n' % args[0]) sys.exit(1) except PermissionError: sys.stderr.write('grc: %s: Permission error\n' % args[0]) sys.exit(1) try: status = os.wait()[1] except OSError: # interrupted system call status = None pass # this is probably not correct sys.exit(status and os.WEXITSTATUS(status))