Skip to content

Instantly share code, notes, and snippets.

@rdpate
Created July 12, 2011 13:16
Show Gist options
  • Save rdpate/1077957 to your computer and use it in GitHub Desktop.
Save rdpate/1077957 to your computer and use it in GitHub Desktop.
#!/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