def function_table(parameters, config):
    qa.LogProcessStart(config, "function_table")
    link_map = config["link_map"]

    syntax_map = config["syntax_map"]
    lines = []
    functions = syntax_map["functions"]
    ordered_functions = sorted(functions)

    categoryDict = dict()
    returnTypeDict = dict()
    functionlist = list()

    for function in ordered_functions:
        link = function + "()"
        if not "`" + link + "`" in link_map:
            qa.LogMissingDocumentation(config, link, ["No documentation"], "")
        category = functions[function]["category"]
        addToDict(categoryDict, category, function)

        returnType = functions[function]["returnType"]
        if returnType == "context": returnType = "class"
        elif returnType in ["ilist", "slist", "rlist"]:
            returnType = "(i,r,s)list"
        elif returnType in ["irange", "rrange"]:
            returnType = "(i,r)range"
        addToDict(returnTypeDict, returnType, function)

    lines.append("### Functions by Category\n\n")
    lines += dictToTable(categoryDict)

    lines.append("### Functions by Return Type\n\n")
    lines += dictToTable(returnTypeDict)

    return lines
def library_include(parameters, config):
    markdown_lines = []
    policy_filename = parameters[0] + ".json"
    policy_json = config.get(policy_filename)
    html_name = config.get("context_current_html")

    qa.LogProcessStart(config, "library_include: %s" % policy_filename)

    if policy_json == None:
        policy_path = config[
            "project_directory"] + "/_generated/" + policy_filename
        if not os.path.exists(policy_path):
            qa.Log(config, "File does not exist: " + policy_path)
            return markdown_lines

        policy_json = json.load(open(policy_path, 'r'))
        config[policy_filename] = policy_json

    # for all bundles and bodies...
    for key in policy_json.keys():
        element_list = policy_json[key]
        current_type = None
        for element in element_list:
            errorString = []
            ignore = False
            namespace = element["namespace"]
            if namespace == "default":
                namespace = None
            name = element["name"]
            element_type = element.get("bundleType")
            if element_type == None:
                element_type = element.get("bodyType")
            if element_type == None:
                qa.Log(config, "element without type: " + name)
                continue

            # start a new block for changed types
            # Assumes that bundles and bodies are grouped by type in library.cf
            print_type = False
            if element_type != current_type:
                current_type = element_type
                print_type = True

            prototype = name
            if namespace:
                prototype = namespace + ":" + prototype

            title = prototype
            link_target = prototype + "()"
            if not namespace:
                link_target = parameters[0] + ":" + link_target
            linkresolver.addLinkToMap(prototype + "()", link_target,
                                      html_name + "#" + prototype, config)

            code_lines = []
            documentation_lines = []
            documentation_dict = dict()
            sourceLines = []
            sourceLine = -1

            try:
                source_path = element["sourcePath"]
                source_path = os.path.normpath(source_path)
                source_file = open(source_path, 'r')
                sourceLine = element["line"] - 1  # zero-based indexing
                sourceLines = source_file.readlines()[sourceLine:]
            except:
                qa.Log(
                    config,
                    "could not include code for element %s - check %s" %
                    (name, source_path))

            if len(sourceLines):
                headerLines = list()
                code_lines.append("\n```cf3\n")
                code_lines.append(sourceLines[0])
                del sourceLines[0]
                in_code = False

                for line in sourceLines:
                    if not in_code:
                        line = line.lstrip()
                        if line.find("{") == 0:
                            in_code = True
                        else:
                            headerLines.append(line)
                    if in_code:
                        code_lines.append(line)
                        # super-naive parser...
                        if line.find("}\n") == 0:
                            break
                code_lines.append("\n```\n")

                # scan comments for doxygen-style documentation
                if len(headerLines):
                    current_tag = None
                    current_param = None
                    current_line = ""
                    for headerLine in headerLines:
                        if headerLine.find("#") != 0:
                            continue

                        headerLine = headerLine[1:].rstrip()
                        # strip single whitespace, but maintain indentation
                        if headerLine.find(" ") == 0:
                            headerLine = headerLine[1:]
                        if headerLine.lstrip().find("@") == 0:
                            current_param = None
                            headerLine = headerLine.lstrip()[1:]
                            current_tag = headerLine
                            tag_end = headerLine.find(" ")
                            if tag_end != -1:
                                current_tag = current_tag[:tag_end]
                                headerLine = headerLine[tag_end + 1:]
                            documentation_dict[current_tag] = ""

                        if current_tag == None:
                            continue
                        if current_tag == "ignore":
                            ignore = True
                            break

                        if current_tag == "param":
                            if current_param == None:
                                current_param = headerLine[:headerLine.find(" "
                                                                            )]
                                headerLine = headerLine[len(current_param) +
                                                        1:]
                                documentation_dict[
                                    "param_" +
                                    current_param] = headerLine + "\n"
                            else:
                                documentation_dict[
                                    "param_" +
                                    current_param] += headerLine + "\n"
                        else:
                            documentation_dict[
                                current_tag] += headerLine + "\n"

                    brief = documentation_dict.get("brief", None)
                    if brief:
                        documentation_lines.append("**Description:** ")
                        documentation_lines.append(brief)
                        documentation_lines.append("\n")
                    else:
                        errorString.append("Missing description")
                    return_doc = documentation_dict.get("return", None)
                    if return_doc:
                        documentation_lines.append("**Return value:** ")
                        documentation_lines.append(return_doc)
                        documentation_lines.append("\n")
                else:  # no header lines
                    errorString.append("No documentation")
            else:  # no source lines
                errorString.append(
                    "No source code or unable to read source code")

            if ignore:
                continue
            arguments = element["arguments"]
            argument_idx = 0
            argument_lines = []
            while argument_idx < len(arguments):
                if argument_idx == 0:
                    prototype += "("
                    argument_lines.append("**Arguments:**\n\n")
                argument = arguments[argument_idx]
                prototype += argument
                argument_line = "* ```" + argument + "```"

                # if we have already found documentation for this, use it
                param_line = documentation_dict.get("param_" + argument)
                if param_line == None:
                    errorString.append("No documentation for parameter %s" %
                                       argument)
                if param_line != None:
                    argument_line += ": " + param_line
                # find out where the argument is being used
                elif key == "bundles":
                    for promise_type in element["promiseTypes"]:
                        promise_type_link = "`" + promise_type["name"] + "`"
                        for context in promise_type["contexts"]:
                            for promise in context["promises"]:
                                promiser = promise["promiser"]
                                if promiser.find("(" + argument + ")") != -1:
                                    argument_line += ", used as promiser of type " + promise_type_link
                                    argument_line += "\n"
                                else:
                                    argument_line += resolveAttribute(
                                        promise["attributes"], argument)
                                    if len(argument_line):
                                        argument_line += " of " + promise_type_link + " promiser *" + promiser + "*"
                    argument_line += "\n"
                elif key == "bodies":
                    for context in element["contexts"]:
                        argument_line += resolveAttribute(
                            context["attributes"], argument)
                    argument_line += "\n"

                argument_lines.append(argument_line)
                argument_idx += 1
                if argument_idx == len(arguments):
                    prototype += ")"
                else:
                    prototype += ", "

            if print_type:
                link_map = config["link_map"]
                if ("`body %s`" % current_type) in link_map:
                    printable_type = "[%s]%s bodies" % (
                        current_type, link_map["`body %s`" % current_type][0])
                elif ("`bundle %s`" % current_type) in link_map:
                    printable_type = "[%s]%s bundles" % (
                        current_type,
                        link_map["`bundle %s`" % current_type][0])
                elif ("`%s`" % current_type) in link_map:
                    printable_type = "[%s]%s %s" % (
                        current_type, link_map["`%s`" % current_type][0], key)
                elif key == "bundles":
                    printable_type = "%s [bundles][bundles]" % current_type
                else:
                    printable_type = current_type
                markdown_lines.append("### %s\n" % printable_type)
                markdown_lines.append("\n")

            markdown_lines.append("#### " + title + " ####\n")
            markdown_lines.append("\n")
            markdown_lines.append("**Prototype:** `" + prototype + "`\n")
            markdown_lines.append("\n")
            if len(documentation_lines):
                markdown_lines.append(documentation_lines)
                markdown_lines.append("\n")
            if len(argument_lines):
                markdown_lines.append(argument_lines)
                markdown_lines.append("\n")
            if len(code_lines):
                markdown_lines.append("**Implementation:**\n")
                markdown_lines.append("\n")
                markdown_lines.append(code_lines)
                markdown_lines.append("\n")
            markdown_lines.append("\n")
            if len(errorString):
                locationString = "`in library `" + os.path.relpath(
                    source_path) + "` (%d)" % sourceLine
                qa.LogMissingDocumentation(config, prototype, errorString,
                                           locationString)
                errorString = []

    if len(markdown_lines) == 0:
        qa.Log(config, "Failure to include " + parameters[0])

    return markdown_lines
def syntax_map(parameters, config):
    qa.LogProcessStart(config, "syntax_map for %s" % parameters[0])
    syntax_map = config["syntax_map"]
    lines = document_syntax_map(syntax_map, parameters[0], config)
    return lines
def apply(config):
	qa.LogProcessStart(config, "Applying Link Map")
	markdown_files =  config["markdown_files"]
	for file in markdown_files:
		applyLinkMap(file, config)