Generates the fortran code for the pysave interface module procedure
    of the specified type and dimensionality.
    
    :arg D: the integer dimensionality of the variable that is having its
      value set from the file.
    :arg dtype: the fortran data type that the subroutine will be reading data
      for. Can be ["real", "integer", "logical", "complex", "character"].
    :arg kind: the precision/kind information for the type. Can be one of
      ["dp", "sp"] for double/single precision real, integer or complex types.
    :arg suffix: not actually used by the routine; in the signature for compatibility
      with the automatic generation of the code.

def pysave(D, dtype, kind, suffix=None):
    """Generates the fortran code for the pysave interface module procedure
    of the specified type and dimensionality.
    
    :arg D: the integer dimensionality of the variable that is having its
      value set from the file.
    :arg dtype: the fortran data type that the subroutine will be reading data
      for. Can be ["real", "integer", "logical", "complex", "character"].
    :arg kind: the precision/kind information for the type. Can be one of
      ["dp", "sp"] for double/single precision real, integer or complex types.
    :arg suffix: not actually used by the routine; in the signature for compatibility
      with the automatic generation of the code.
    """
    common = {
        "dtype": dtype,
        "D": D,
        "Dx": "({})".format(','.join([":"]*D)) if D >0 else "",
        "suffix": xsuffix[suffix],
        "skind": kind if kind is not None else "",
        "fmtvar": ("character(20) :: FMT" if dtype != "complex"
                   else "character(:), allocatable :: FMT")
    }

    #For character, we use the auto-length arrays.
    if dtype in prec and kind in prec[dtype]:
        common["fmt"] = prec[dtype][kind]
    else:
        common["fmt"] = "*"

    if kind is not None and dtype in kmap:
        common["kind"] = "({})".format(kmap[dtype][kind])
    else:
        common["kind"] = ""

    if D > 0:
        inds = ', '.join(["i{}".format(i+1) for i in range(D-1)])
        if D > 1:
            inds = ', ' + inds
        common["vars"] = "integer :: dims({}){}\n".format(D, inds)
    else:
        common["vars"] = ""

    if D > 0:
        lines = ["dims = shape(variable)",
                 "if (dims({}) .eq. 0) return".format(D)]
        if dtype == "complex":
            rfmt = "2E22.12" if kind == "dp" else "2E19.9"
            lines.append("FMT = '{0}'".format(rfmt))
            fmtloop = "do ifmt=2,dims({0}); FMT = FMT//',1X,{1}';  end do"
            lines.append(fmtloop.format(D, rfmt))
        else:
            lines.append("write(FMT, *) dims({})".format(D))
        common["initial"] = '\n    '.join(lines)
    else:
        common["initial"] = "write(FMT, *) 1"
        
    if D==0:
        if dtype=="character":
            common["write"] = "write(fileunit, {fmt}) trim(adjustl(variable))".format(**common)
        else:
            common["write"] = "write(fileunit, {fmt}) variable".format(**common)
    else:
        lines = []
        if D > 2:
            #Add the shape declaration at the top of the file.
            lines.append("write(fileunit, \"(A, {}i15)\") \"## \", dims".format(D))
        #Next, we make a do loop for each of the dimensions except the last and then
        #write the lines of the last 2D array for each slice.
        for i in range(D-1):
            lines.append("{0}do i{1}=1, dims({1})".format(spacer(2*i), i+1))
            if i == D-3 and D > 2:
                inds = ', '.join(["i{}".format(j+1) for j in range(D-2)])
                fmtstr = "{}write(fileunit, \"(A, {}i15)\") \"## \", {}, 0, 0"
                lines.append(fmtstr.format(spacer(2*(i+1)), D, inds))

        sinds = ', '.join(["i{}".format(j+1) for j in range(D-1)])
        if D > 1:
            sinds = sinds + ', '
        if dtype=="character":
            fmtstr = "{0}call char_write_trimmed(variable({2}:))"
        else:
            fmtstr = "{}write(fileunit, {}) variable({}:)"
        lines.append(fmtstr.format(spacer(2*(D-1)), common["fmt"], sinds))

        #Finally, add the 'end do' statements to close the loops. 
        for i in range(D-2,-1,-1):
            lines.append("{0}end do".format(spacer(2*i), i+1))

        common["write"] = '\n    '.join(lines)

    if dtype=="character":
        common["xname"] = "pysave_{dtype}_{D}d{suffix}".format(**common)
    else:
        common["xname"] = "pysave_{dtype}{skind}_{D}d{suffix}".format(**common)
    
    template = """  subroutine {xname}(variable, filename)
    character(len=*), intent(in) :: filename
    {dtype}{kind}, intent(in) :: variable{Dx}
    {fmtvar}
    {vars}
    integer :: ifmt
    {initial}

    call file_open(filename, len(filename), '{dtype}')
    {write}
    call file_close()
  end subroutine {xname}
    """
    return (common["xname"], template.format(**common))