#!/usr/bin/env python # A tiny Python script to perform substitutions in the NDK documentation # .text input files before processing them with Markdown. # import re import argparse import sys class Filter: def __init__(self,pattern,replacement): self.pattern = re.compile(pattern) self.replacement = replacement def process(self, line): return self.pattern.sub(self.replacement, line) all_filters = [] all_filter_tests = [] def add_filter(pattern, replacement): global all_filters filter = Filter(pattern, replacement) all_filters.append(filter) def add_filter_test(input, expected): global all_filter_tests all_filter_tests.append((input, expected)) def run_all_tests(): global all_filter_tests count = 0 failed_tests = [] for input_string, expected in all_filter_tests: string = input_string print "Testing: '%s'" % input_string, for f in all_filters: string = f.process(string) if string != expected: failed_tests.append((input_string, expected, string)) print " KO!" print " Got : '%s'" % string print " Expected: '%s'" % expected else: print "ok." count += 1 return count, failed_tests # Auto-linkify documentation # # d/NDK-BUILD # -> [NDK-BUILD](NDK-BUILD.html) # add_filter(r"(^|\s+)d/([^\s.]+)", r"\1[\2](\2.html)") add_filter_test("d/NDK-BUILD", "[NDK-BUILD](NDK-BUILD.html)") add_filter_test("aa d/NDK-BUILD", "aa [NDK-BUILD](NDK-BUILD.html)") add_filter_test("ad/NDK-BUILD", "ad/NDK-BUILD") add_filter_test("d/NDK-BUILD.", "[NDK-BUILD](NDK-BUILD.html).") # Auto-linkify documentation # NDK-BUILD.html # -> [NDK-BUILD](NDK-BUILD.html) # add_filter(r"(^|\s+)([A-Z0-9-]+)\.html", r"\1[\2](\2.html)") add_filter_test("NDK-BUILD.html", "[NDK-BUILD](NDK-BUILD.html)") add_filter_test("NDK-BUILD.html.", "[NDK-BUILD](NDK-BUILD.html).") add_filter_test("aa NDK-BUILD.html", "aa [NDK-BUILD](NDK-BUILD.html)") add_filter(r"(^|\s+)(\$NDK/docs/|docs/)([A-Z0-9_-]+)\.html", r"\1[\3](\3.html)") add_filter_test("$NDK/docs/ANDROID-MK.html", "[ANDROID-MK](ANDROID-MK.html)") add_filter_test("See docs/ANDROID-MK.html.", "See [ANDROID-MK](ANDROID-MK.html).") # Auto quote script file. # make-standalone-toolchain.sh # -> `make-standalone-toolchain.sh` add_filter(r"(^|\s+)([^\s]+\.sh)", r"\1`\2`") add_filter_test("make-standalone-toolchain.sh", "`make-standalone-toolchain.sh`") # Auto-linkify bug entries: # # http://b.android.com/ # or http://code.google.com/p/android/issues/detail?id= # -> [b/](http://b.android.com/) # add_filter( r"http://(code\.google\.com/p/android/issues/detail\?id=|b\.android\.com/)([0-9]+)", r"[b/\2](http://b.android.com/\2)") add_filter_test(r"See http://b.android.com/12345", r"See [b/12345](http://b.android.com/12345)") add_filter_test(r"See http://code.google.com/p/android/issues/detail?id=12345", r"See [b/12345](http://b.android.com/12345)") # Auto-linkify bug shortcuts like b/1000 # # b/ after space or start of line # -> [b/](http://b.android.com/) add_filter( r"(^|\s+)(b/([0-9]+))", r"\1[\2](http://b.android.com/\3)") add_filter_test(r"b/12345", r"[b/12345](http://b.android.com/12345)") add_filter_test(r"See b/12345.", r"See [b/12345](http://b.android.com/12345).") add_filter_test(r"[b/12345](....)", r"[b/12345](....)") # Auto-linkify patch entries. # https://android-review.googlesource.com/#/c/ # -> [r/](https://android-review.googlesource.com/#/c/) add_filter( r"(^|\s+)(https://android-review\.googlesource\.com/\#/c/([0-9]+))", r"\1[r/\3](\2)") add_filter_test(r"https://android-review.googlesource.com/#/c/12345", r"[r/12345](https://android-review.googlesource.com/#/c/12345)") # Auto-linkify anything # http://www.example.com # -> add_filter(r"(^|\s+)((ssh|http|https|ftp)://[^\s]+)", r"\1<\2>") add_filter_test("http://example.com", "") # r/ not followed by (...) # -> [r/](https://android-review.googlesource.com/#/c/) add_filter( r"(^|\s+)(r/([0-9]+))", r"\1[\2](https://android-review.googlesource.com/#/c/\3)") add_filter_test( r"r/12345", r"[r/12345](https://android-review.googlesource.com/#/c/12345)") # Auto format __ANDROID__, __ARM_ARCH*__, etc.. # __XXX__ # -> `__XXX__` add_filter(r"(__[A-Z][^\s]*)", r"`\1`") add_filter_test(r"__ANDROID__", r"`__ANDROID__`") add_filter_test(r"__ARM_ARCH_5*__", r"`__ARM_ARCH_5*__`") # Auto-format compiler/linker flags: # -O2 # -> `-O2` add_filter(r"(^|\s+)(\-[\w][^\s]+)", r"\1`\2`") add_filter_test(r"-O2", r"`-O2`") add_filter_test(r" -fPIC", r" `-fPIC`") add_filter_test(r" -mfpu=neon xxx", r" `-mfpu=neon` xxx") add_filter_test(r" -mfpu=vfpd3-d16", r" `-mfpu=vfpd3-d16`") # Auto-format LOCAL_XXX, APP_XXX and NDK_XXX variables # as well as assignments. add_filter(r"(^|\s+)([A-Z_0-9]+=[^\s]+)", r"\1`\2`") add_filter_test("Use NDK_DEBUG=release", "Use `NDK_DEBUG=release`") add_filter_test("NDK_HOST_32BIT=1", "`NDK_HOST_32BIT=1`") add_filter(r"(^|\s+)((APP_|NDK_|LOCAL_)[A-Z0-9_]*)", r"\1`\2`") add_filter_test("LOCAL_MODULE", "`LOCAL_MODULE`") # Auto-format __cxa_xxxxx and other prefixes. # add_filter(r"(^|\s+)((__cxa_|__dso_|__aeabi_|__atomic_|__sync_)[A-Za-z0-9_]+)", r"\1`\2`") add_filter_test("__cxa_begin_cleanup", "`__cxa_begin_cleanup`") add_filter_test("__dso_handle", "`__dso_handle`") add_filter_test("__aeabi_idiv2", "`__aeabi_idiv2`") add_filter_test("See __cxa_cleanup.", "See `__cxa_cleanup`.") re_blockquote = re.compile(r"^ ") def process(input_file, output_file): # Process lines, we need to take care or _not_ processing # block-quoted lines. For our needs, these begin with 8 spaces. # in_list = False margins = [ 0 ] margin_index = 0 for line in input_file: do_process = True if len(line.strip()): if not re_blockquote.match(line): for f in all_filters: line = f.process(line) output_file.write(line) def main(): parser = argparse.ArgumentParser(description=''' Perform .text substitution before Markdown processing.''') parser.add_argument( '-o', '--output', help="Specify output file, stdout otherwise.", dest='output', default=None ) parser.add_argument( '--run-checks', help="Run internal unit tests.", action='store_true', dest='run_checks', default=False ) parser.add_argument( 'input_file', help="Input file, stdin if not specified.", nargs="?", default=None ) args = parser.parse_args() if args.run_checks: count, failed_tests = run_all_tests() if failed_tests: sys.stderr.write("ERROR: %d tests out of %d failed:\n" % (len(failed_tests), count)) for failed in failed_tests: sys.stderr.write(" '%s' -> '%s' (expected '%s')\n" % (failed[0], failed[2], failed[1])) sys.exit(1) else: print "%d tests passed. Congratulations!" % count sys.exit(0) if args.input_file: try: in_file = open(args.input_file, "rt") except: sys.stderr.write("Error: Can't read input file: %s: %s\n" % args.input_file, repr(e)) sys.exit(1) else: in_file = sys.stdin if args.output: try: out_file = open(args.output, "wt") except: sys.stderr.write("Error: Can't open output file: %s: %s\n" % args.output, repr(e)) sys.exit(1) else: out_file = sys.stdout process(in_file, out_file) out_file.close() in_file.close() sys.exit(0) if __name__ == '__main__': main()