Created
July 12, 2011 13:16
-
-
Save rdpate/1077957 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2.6 | |
"""xsel-like C++ front-end | |
Can be used in source as hashbang: | |
#!/usr/bin/env c++sel | |
// rest of code | |
A hashbang, if any, is stripped before compiling. | |
""" | |
import optparse | |
import os | |
import subprocess | |
import sys | |
TMP_OBJ = os.path.expanduser("~/tmp/c++sel.o") | |
TMP_EXEC = os.path.expanduser("~/tmp/c++sel.out") | |
DEFAULTS = { | |
"CXX": "g++", | |
"CXXFLAGS": "-Wall -Wextra -Wfloat-equal -Wundef -fdiagnostics-show-option -std=c++98", | |
"LDFLAGS": "-lboost_filesystem", | |
} | |
PREAMBLE = """\ | |
#line 1 "PREAMBLE" | |
#include <assert.h> | |
#include <limits.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <algorithm> | |
#include <bitset> | |
#include <complex> | |
#include <deque> | |
#include <exception> | |
#include <fstream> | |
#include <functional> | |
#include <iomanip> | |
#include <iostream> | |
#include <iterator> | |
#include <list> | |
#include <locale> | |
#include <map> | |
#include <memory> | |
#include <queue> | |
#include <set> | |
#include <sstream> | |
#include <stack> | |
#include <stdexcept> | |
#include <utility> | |
#include <vector> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <fcntl.h> | |
#include <boost/version.hpp> | |
#include <boost/any.hpp> | |
#include <boost/array.hpp> | |
#include <boost/assert.hpp> | |
#include <boost/assign.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/checked_delete.hpp> | |
#include <boost/filesystem.hpp> | |
#include <boost/format.hpp> | |
#include <boost/implicit_cast.hpp> | |
#include <boost/integer.hpp> | |
#include <boost/integer_traits.hpp> | |
#include <boost/iterator/counting_iterator.hpp> | |
#include <boost/iterator_adaptors.hpp> | |
#include <boost/lexical_cast.hpp> | |
#include <boost/multi_array.hpp> | |
#include <boost/next_prior.hpp> | |
#include <boost/noncopyable.hpp> | |
#include <boost/optional.hpp> | |
#include <boost/range.hpp> | |
//#include <boost/rational.hpp> | |
#include <boost/ref.hpp> | |
#include <boost/scoped_array.hpp> | |
#include <boost/scoped_ptr.hpp> | |
#include <boost/shared_array.hpp> | |
#include <boost/shared_ptr.hpp> | |
#include <boost/smart_ptr.hpp> | |
#include <boost/tokenizer.hpp> | |
#include <boost/utility.hpp> | |
#include <boost/variant.hpp> | |
#include <kniht/macros> | |
#include <kniht/streamutil> | |
#define STRINGIZE KNIHT_STRINGIZE | |
using namespace kniht::container_inserters; | |
using namespace std; | |
""" | |
def check_output(*popenargs, **kwargs): | |
"""Run command with arguments and return its output as a byte string. | |
Source: http://svn.python.org/view/python/trunk/Lib/subprocess.py?view=markup | |
""" | |
from subprocess import Popen, PIPE, CalledProcessError | |
if 'stdout' in kwargs: | |
raise ValueError('stdout argument not allowed, it will be overridden.') | |
process = Popen(stdout=PIPE, *popenargs, **kwargs) | |
output, unused_err = process.communicate() | |
retcode = process.poll() | |
if retcode: | |
cmd = kwargs.get("args") | |
if cmd is None: | |
cmd = popenargs[0] | |
raise CalledProcessError(retcode, cmd, output=output) | |
return output | |
def main(args): | |
def _parse_args(args): | |
op = optparse.OptionParser(usage="%prog [OPTION..] [FILE]", add_help_option=False) | |
op.add_option("--help", action="help", help="show help message and exit") | |
op.add_option("-v", "--verbose", action="store_true", default=False, | |
help="show subcommands before executing them") | |
op.add_option("-c", "--compile", action="store_true", default=False, | |
help="compile only") | |
op.add_option("-s", "--show", action="store_true", default=False, | |
help="show input only") | |
op.add_option("--input", type="choice", default="default", | |
choices=["default", "clipboard", "primary", "stdin"], | |
help="choose input: clipboard, primary, stdin") | |
op.add_option("-b", dest="input", action="store_const", const="clipboard", | |
help="--input=clipboard") | |
op.add_option("-p", dest="input", action="store_const", const="primary", | |
help="--input=primary") | |
op.add_option("-i", dest="input", action="store_const", const="stdin", | |
help="--input=stdin") | |
op.add_option("--no-preamble", dest="preamble", action="store_false", default=True, | |
help="don't add preamble") | |
op.add_option("--show-preamble", action="store_true", default=False, | |
help="show preamble and exit") | |
op.add_option("--hello-world", action="store_true", default=False, | |
help="use hello world code") | |
op.add_option("-t", "--time", action="store_true", default=False, | |
help="time execution") | |
op.add_option("--std", default=None, | |
help="pass -std=STD to compiler") | |
op.add_option("--tabstop", type="int", default=8, | |
help="tab stop or \"width\"") | |
opts, args = op.parse_args(args) | |
if opts.hello_world and args: | |
op.error("cannot specify --hello-world and a filename") | |
if len(args) > 1: | |
op.error("unexpected arguments") | |
if args and opts.input != "default": | |
op.error("cannot specify --input with filename argument") | |
if opts.input == "default": | |
opts.input = "stdin" if not os.isatty(sys.stdin.fileno()) else "clipboard" | |
return opts, args | |
opts, args = _parse_args(args) | |
if opts.show_preamble: | |
code = PREAMBLE.rstrip("\n").split("\n") | |
assert code[0].startswith("#line ") | |
code.pop(0) # remove #line directive | |
for lineno, line in enumerate(code, start=1): | |
print "%3d %s" % (lineno, line) | |
return | |
if opts.hello_world: | |
code = r"""int main() { cout << "Hello, world!\n"; }""" | |
input_filename = "<input>" | |
elif opts.input == "stdin": | |
code = sys.stdin.read() | |
input_filename = "<input>" | |
elif not args: | |
code = check_output(["xsel", {"primary": "-p", "clipboard": "-b"}[opts.input]]) | |
input_filename = "<input>" | |
else: | |
with open(args[0]) as f: | |
code = f.read() | |
input_filename = args[0] | |
code = code.rstrip("\n").expandtabs(opts.tabstop).split("\n") | |
skip_lines = 0 | |
if code[0].startswith("#!"): | |
skip_lines += 1 | |
if opts.show: | |
for lineno, line in enumerate(code, start=1): | |
print "%3d %s" % (lineno, line) | |
return | |
CXX = os.environ.get("CXX", DEFAULTS["CXX"]) | |
CXXFLAGS = os.environ.get("CXXFLAGS", DEFAULTS["CXXFLAGS"]) | |
LDFLAGS = os.environ.get("LDFLAGS", DEFAULTS["LDFLAGS"]) | |
USER_INCLUDE = os.path.expanduser("~/.local/include") | |
if os.path.isdir(USER_INCLUDE): | |
CXXFLAGS += " -I" + USER_INCLUDE | |
cmd = CXX.split() + CXXFLAGS.split() + ["-xc++", "-"] | |
if opts.std: | |
cmd += ["-std=" + opts.std] | |
if opts.compile: | |
cmd += ["-c", "-o", TMP_OBJ] | |
else: | |
cmd += ["-o", TMP_EXEC] + LDFLAGS.split() | |
if opts.verbose: | |
print "+", " ".join(cmd) | |
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE) | |
code[:skip_lines] = ["#line %d \"%s\"" % (skip_lines + 1, input_filename)] | |
code = "\n".join(code) + "\n" | |
if opts.preamble: | |
code = PREAMBLE + code | |
proc.communicate(code) | |
r = proc.wait() | |
if r: | |
return r | |
if opts.compile: | |
print "Success" | |
return | |
if opts.verbose: | |
print "+", TMP_EXEC | |
if opts.time: | |
proc = subprocess.Popen(["bash", "-c", "time " + TMP_EXEC]) | |
else: | |
proc = subprocess.Popen([TMP_EXEC]) | |
return proc.wait() | |
if __name__ == "__main__": | |
try: | |
sys.exit(main(sys.argv[1:])) | |
except KeyboardInterrupt: | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment