[BACK]Return to lcomp.ls CVS log [TXT][DIR] Up to [Development] / projects / ogl-sample / main / glx / lib

File: [Development] / projects / ogl-sample / main / glx / lib / lcomp.ls (download)

Revision 1.1, Wed Jan 26 10:31:11 2000 UTC (17 years, 9 months ago) by ljp
Branch: MAIN

Initial revision

##############################################################################
#
# License Applicability. Except to the extent portions of this file are
# made subject to an alternative license as permitted in the SGI Free
# Software License B, Version 1.0 (the "License"), the contents of this
# file are subject only to the provisions of the License. You may not use
# this file except in compliance with the License. You may obtain a copy
# of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
# Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
# 
# http://oss.sgi.com/projects/FreeB
# 
# Note that, as provided in the License, the Software is distributed on an
# "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
# DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
# CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
# PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
# 
# Original Code. The Original Code is: OpenGL Sample Implementation,
# Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
# Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
# Copyright in any portions created by third parties is as indicated
# elsewhere herein. All Rights Reserved.
# 
# Additional Notice Provisions: The application programming interfaces
# established by SGI in conjunction with the Original Code are The
# OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
# April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
# 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
# Window System(R) (Version 1.3), released October 19, 1998. This software
# was created using the OpenGL(R) version 1.2.1 Sample Implementation
# published by SGI, but has not been independently verified as being
# compliant with the OpenGL(R) version 1.2.1 Specification.
#
##############################################################################
#
#   Generate the list compilation routines and the GLX client transport
#   routines.
#
#   $Date$ $Revision$
#   $Header$
#
##############################################################################

function initialize() {

    # TYPEMAP should be defined on the command line that invokes libspec
    typeMapFile = TYPEMAP;
    _readWireFile();

    # Functions that will be generated, should be defined on command line.
    funcs = FUNCS;

    noship = 		(NOSHIP ~ /yes/);
    genTransDraw =    	(funcs ~ /transdraw/);
    genTransSingle =  	(funcs ~ /transsingle/);
    genTransVendpriv = 	(funcs ~ /transvendpriv/);
    genSpecRender =   	(funcs ~ /specrender/);
    genEncodeRender = 	(funcs ~ /encoderender/);
    genSpecSingle =   	(funcs ~ /specsingle/);
    genSpecVendpriv = 	(funcs ~ /specvendpriv/);
    genEncodeSingle = 	(funcs ~ /encodesingle/);
    genEncodeVendpriv =	(funcs ~ /encodevendpriv/);
    genTrans = 	     	genTransDraw || genTransSingle || genTransVendpriv;
    genSpec = 		genSpecRender || genSpecSingle || genSpecVendpriv;
    genEncode = 	genEncodeRender || genEncodeSingle || genEncodeVendpriv;
    
    #
    # Try to encapsulate the differences between different output here.
    #
    
    if (genTransDraw) {
	functionPrefix = "gl";
	opcodePrefix = "X_GLrop_";
	macroPrefix = "__GLX";
	shortMacroPrefix = "__GLX";
	GLXheaders = 1;
    } else if (genTransSingle) {
	functionPrefix = "gl";
	opcodePrefix = "X_GLsop_";
	macroPrefix = "__GLX_SINGLE";
	shortMacroPrefix = "__GLX";
	GLXheaders = 1;
    } else if (genTransVendpriv) {
	functionPrefix = "gl";
	opcodePrefix = "X_GLvop_";
	macroPrefix = "__GLX_VENDPRIV";
	shortMacroPrefix = "__GLX";
	GLXheaders = 1;
    }

    #
    # Set the maximum size of fixed-sized commands; use to optimize space
    # checking of the transport buffer or list buffer.
    #
    MAX_FIXED_SIZE = 80;
    
    #
    # Partial names of macros used to send each wire type.
    #
    cast["enum"] =	"LONG"
    cast["boolean"] =	"CHAR"
    cast["bitfield"] =	"LONG"
    cast["byte"] =	"CHAR"
    cast["short"] =	"SHORT"
    cast["int"] =	"LONG"
    cast["sizei"] =	"LONG"
    cast["ubyte"] =	"CHAR"
    cast["ushort"] =	"SHORT"
    cast["uint"] =	"LONG"
    cast["float"] =	"FLOAT"
    cast["clampf"] =	"FLOAT"
    cast["double"] =	"DOUBLE"
    cast["clampd"] =	"DOUBLE"
    cast["void"] =      "VOID"
      
    #
    # X protocol wire types
    #
    proto["enum"] =	"ENUM"
    proto["boolean"] =	"BOOL"
    proto["bitfield"] =	"BITFIELD"
    proto["byte"] =	"INT8"
    proto["short"] =	"INT16"
    proto["int"] =	"INT32"
    proto["sizei"] =	"INT32"
    proto["ubyte"] =	"CARD8"
    proto["ushort"] =	"CARD16"
    proto["uint"] =	"CARD32"
    proto["float"] =	"FLOAT32"
    proto["clampf"] =	"FLOAT32"
    proto["double"] =	"FLOAT64"
    proto["clampd"] =	"FLOAT64"
    proto["void"] =     "VOID"		# these will have to be handcoded
    #
    # Define the return types for the few routines that have them (and are
    # generated).
    #
    protoReturn["boolean"] =	"BOOL32"
    protoReturn["int"] =	"INT32"
    protoReturn["uint"] =	"CARD32"
      
    #
    # Byte sizes of wire types.
    #
    xfer_size["enum"] =		"4"
    xfer_size["boolean"] =	"1"
    xfer_size["bitfield"] =	"4"
    xfer_size["byte"] =		"1"
    xfer_size["short"] =	"2"
    xfer_size["int"] =		"4"
    xfer_size["sizei"] =	"4"
    xfer_size["ubyte"] =	"1"
    xfer_size["ushort"] =	"2"
    xfer_size["uint"] =		"4"
    xfer_size["float"] =	"4"
    xfer_size["clampf"] =	"4"
    xfer_size["double"] =	"8"
    xfer_size["clampd"] =	"8"
    xfer_size["void"] =         "1"		# A lie, but good enough

    #
    # Include header files.
    #
    if (GLXheaders) {
	if (genTransSingle) {
	    printf "#include \"packsingle.h\"\n\n";
	} else if (genTransDraw) {
	    printf "#include \"packrender.h\"\n\n";
	} else if (genTransVendpriv) {
	    printf "#include \"packvendpriv.h\"\n\n";
	}
    }
}

function main( i, param, cmdlen) {

    #
    # Filter out unwanted routines.
    #
    if (genTransSingle) {
	if (!("glxsingle" in propList)) return;
	if (!(("dlflags", "notlistable") in propListValues)) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (("glxflags", "client-handcode") in propListValues) return;
    } else if (genTransVendpriv) {
	if (!("glxvendorpriv" in propList)) return;
	if (!(("dlflags", "notlistable") in propListValues)) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (("glxflags", "client-handcode") in propListValues) return;
    } else if (genTransDraw) {
	if (("dlflags", "notlistable") in propListValues) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (("glxflags", "client-handcode") in propListValues) return;
    } else if (genSpecRender || genEncodeRender) {
	if (("dlflags", "notlistable") in propListValues) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (noship) {
	    if (!(("glxflags", "client-handcode") in propListValues)) return;
	} else {
	    if (("glxflags", "client-handcode") in propListValues) return;
	}
    } else if (genSpecSingle || genEncodeSingle) {
        if (!("glxsingle" in propList)) return;
	if (!(("dlflags", "notlistable") in propListValues)) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (noship) {
	    if (!(("glxflags", "client-handcode") in propListValues)) return;
	} else {
	    if (("glxflags", "client-handcode") in propListValues) return;
	}
    } else if (genSpecVendpriv || genEncodeVendpriv) {
        # No longer handled with SpecSingles above, since that led
        #   to EXTensions creeping into the core GLX protocol specification.
	if (!("glxvendorpriv" in propList)) return;
	if (!(("dlflags", "notlistable") in propListValues)) return;
	if (("glxflags", "client-only") in propListValues) return;
	if (noship) {
	    if (!(("glxflags", "client-handcode") in propListValues)) return;
	} else {
	    if (("glxflags", "client-handcode") in propListValues) return;
	}
    }

    #
    # Write the opcode.  Routines that have vector equivalents get mapped to
    # them.  We have to check this here because the protocol generators need
    # to bail out now if there are vectorequivs.
    #
    if ("vectorequiv" in propList) {
	if (genSpec || genEncode) return;
	opcodeName = propList["vectorequiv"];
	sub( ",", "", opcodeName);
    } else {
	if ("glxropcode" in propList) {
	    opcodeName = functionName;
	    opcode = propList["glxropcode"];
	    sub( ",", "", opcode);
	} else if ("glxsingle" in propList) {
	    opcodeName = functionName;
	    opcode = propList["glxsingle"];
	    sub( ",", "", opcode);
	} else if ("glxvendorpriv" in propList) {
	    opcodeName = functionName;
	    opcode = propList["glxvendorpriv"];
	    sub( ",", "", opcode);
	} else {
	    specError("No glxropcode, glxvendorpriv, or glxsingle defined for " functionName);
	}
    }

    fname = functionName;

    #
    # Set some flags for each parameter for convenience.
    # (this function is in the list utils)
    #
    setPerParamFlags();

    if (genEncode && hasInCompSizeParam && !noship) {
	return;
    }

    #
    # Sort all parameters, largest elements first, so that we don't have to
    # word-align them individually. (this function is in the list utils)
    #
    sortParams();

    #
    # Compute the total size of the command going "in" to the server.
    #
    computeInCmdSize();
    computeOutCmdSize();

    #
    # Intercepted routines have a special prefix.
    # Note: glFlush is the only client-intercept so far.
    if (("glxflags", "client-intercept") in propListValues &&
	(genTransDraw || genTransSingle || genTransVendpriv)) {
	internalPrefix = "__";
    } else {
	internalPrefix = "";
    }

    #
    # Declare the procedure.
    #
    if (genTrans) {
    	printf "%s %s%s%s", returnType, internalPrefix, functionPrefix, fname;
    	printf "(";
    	outputCArglist();
    	printf ")\n";
    	printf "{\n";
    	if (genTransSingle) {
		printf "\t__GLX_SINGLE_DECLARE_VARIABLES();\n";
    	}else if (genTransVendpriv) {
		printf "\t__GLX_VENDPRIV_DECLARE_VARIABLES();\n";
    	} else if (genTransDraw) {
		printf "\t__GLX_DECLARE_VARIABLES();\n";
    	}
    } else if (genSpecRender) {
	printf ".Or %s\n", functionName;
    } else if (genSpecSingle) {
	printf ".Na %s\n", functionName;
	printf ".Rq\n";
	printf ".Pa tag GLX_CONTEXT_TAG\n";
    } else if (genSpecVendpriv) {
	printf ".Na %s\n", functionName;
	printf ".Rq\n";
	printf ".Pa tag GLX_CONTEXT_TAG\n";
    } else if (genEncode) {
        printf "\\Ao{%s}\n", functionName;
    }

    #
    # Declare local to store computed size of variable-sized arrays.
    #
    if (hasInCompSizeParam && genTrans) {
	printf "\tcompsize = %s;\n",
	    getCompSizeParamList(inCompSizeParamIndex);
    }

    #
    # Declare a local to store the return value.  Only genTransSingles do this.
    #
    if (hasReturn && genTrans) {
	printf "\t%s    retval = 0;\n", returnType;
    }

    if (genTransSingle && \
	(hasReturn || numOutFixParams > 0 || numOutVarParams > 0)) {
        printf "\txGLXSingleReply reply;\n";
    }

    if (genTransVendpriv && \
	(hasReturn || numOutFixParams > 0 || numOutVarParams > 0)) {
        printf "\txGLXVendorPrivReply reply;\n";
    }

    if (genTransSingle) {
	printf "\t__GLX_SINGLE_LOAD_VARIABLES();\n";
    } else if (genTransVendpriv) {
	printf "\t__GLX_VENDPRIV_LOAD_VARIABLES();\n";
    } else if (genTransDraw) {
	printf "\t__GLX_LOAD_VARIABLES();\n";
    }

    #
    # Make a list of non-redundant ParamSizeParams, because otherwise
    # the same size param will be checked more than once.
    #
    clearArray(inParamSizeParamCount);
    for (i in inParamSizeParamIndices) {
       inParamSizeParamCount[arrayCount[inParamSizeParamIndices[i]]];
    }

    #
    # If a size parameter is invalid, ignore the command.
    #
    for (count in inParamSizeParamCount) {
    	if (genTrans) {
	    if (hasReturn) {
		printf "\tif \(%s < 0\) return retval;\n", count;
	    }
	    else {
		printf "\tif \(%s < 0\) return;\n", count;
	    }
    	}
    }

    #
    # Compute sizes of all "in" parameters and the total size of the
    # command.  The fixed length is initialized to 4 to include opcode (2)
    # and size of command (2).
    #
    if (genTransDraw || genSpec || genEncode) {
        inFixCmdSize += 4;
    }
    if (numInVarParams > 0 ) {
	if (inVarParamsNeedPad) {
	    cmdlen = sprintf("%s_PAD\(%d%s\)", shortMacroPrefix, inFixCmdSize, \
		             inVarCmdSize);
	} else {
	    cmdlen = sprintf("%d%s", inFixCmdSize, inVarCmdSize);
	}
	if (genTrans) printf "\tcmdlen = %s;\n", cmdlen;
    } else {
	cmdlen = inFixCmdSize;
    }

    #
    # Do whatever is needed to initialize the buffer space before we start
    # writing parameters.
    #
    if (numInVarParams > 0) {
	str = "cmdlen";
    } else {
	str = cmdlen;
    }
    if (genTrans) {
	if (genTransVendpriv) {
	    if (hasReturn || ((numOutFixParams + numOutVarParams)) > 0) {
		printf "\t%s_BEGIN(%s,%s%s,%s);\n", macroPrefix,\
		     "X_GLXVendorPrivateWithReply", opcodePrefix, opcodeName, str;
	    } else {
		printf "\t%s_BEGIN(%s,%s%s,%s);\n", macroPrefix,\
		     "X_GLXVendorPrivate", opcodePrefix, opcodeName, str;
	    }
	} else {
	    printf "\t%s_BEGIN(%s%s,%s);\n", macroPrefix, opcodePrefix,\
		opcodeName, str;
	}
    }

    #
    # Write command header for protocol encoding.
    #
    if (genEncodeRender) {
        printf "    \\paramline{2}{%s}{rendering command length}\n", str;
        printf "    \\paramline{2}{%s}{rendering command opcode}\n", opcode;
    } else if (genEncodeSingle) {
        printf "    \\paramline{1}{\\glp{CARD8}}{opcode (X assigned)}\n";
        printf "    \\paramline{1}{%s}{GLX opcode}", opcode;
	# All singles have a fixed "in" command length, so we just divide by
	# 4 to get the length. Add 1 for the X header.
        printf "    \\paramline{2}{%s}{request length}\n", (str/4)+1;
        printf "    \\paramline{4}{\\glp{GLX\\_CONTEXT\\_TAG}}{context tag}\n", str;
    } else if (genEncodeVendpriv) {
        # Uses different protocol than Single commands - either
        # VendorPrivate or VendorPrivateWithReply.
        # XXX TO BE DONE
        printf "    \\paramline{1}{\\glp{CARD8}}{opcode (X assigned)}\n";
        printf "    \\paramline{1}{???}{VENDOR-PRIVATE OPCODE GOES HERE}\n", opcode;
        printf "    \\paramline{}{}{\\bfWarning: vendor-private Encode/Spec not done!}\n";
    }

    #
    # Write fixed size parameters.  These are scalars or fixed-size arrays.
    #
    if (genTransSingle || genTransVendpriv) {
	offset = 0;
    } else if (genTransDraw) {
	offset = 4;
    }
    for (j=1; j <= numInFixParams; j++) {

	i = sortedInFixParams[j];
	param = paramName[i];
	ttype = paramTransferType[param];

	if (isArray[i]) {
	    #
	    # Write fixed-size arrays.
	    #
	    if (arrayCount[i] <= 4) {
		#
	    	# For small arrays, just copy elements one at a time.
		#
		for (k=0; k < arrayCount[i]; k++) {
	    	    if (genTrans) {
			printf "\t%s_PUT_%s(%d,%s[%d]);\n", macroPrefix,
			    _cast[i], offset, param, k;
		    }
		    if (genSpecRender) {
			printf ".Op %s[%d] %s\n", param, k, _proto[i];
		    }
		    if (genSpecSingle || genSpecVendpriv) {
			printf ".Pa %s[%d] %s\n", param, k, _proto[i];
		    }
		    if (genEncode) {
                        printf "    \\paramline{%d}{\\glp{%s}}{%s[%d]}\n", \
                            _xfer_size[i], _proto[i], param, k;
		    }
		    offset += xfer_size[_wire[i]];
		}
	    } else {
	    	if (genTrans) {
		    printf "\t%s_PUT_%s_ARRAY(%d,%s,%s);\n", shortMacroPrefix,
			_cast[i], offset, param, arrayCount[i];
		}
		if (genSpecRender) {
		    printf ".Op %s LISTof%s\n", param, _proto[i];
		}
		if (genSpecSingle || genSpecVendpriv) {
		    printf ".Pa %s LISTof%s\n", param, _proto[i];
		}
		if (genEncode) {
                    printf "    \\paramline{%s}{\\glp{LISTof%s}}{%s}\n",
			_xfer_size[i]*arrayCount[i], _proto[i], param;
		}
		offset += xfer_size[_wire[i]] * arrayCount[i];
     	    }
	} else {
	    #
	    # Write scalars.
	    #
	    if (ttype == "reference") deref="*";
	    else deref="";
	    if (genTrans) {
		printf "\t%s_PUT_%s(%d,%s%s);\n", macroPrefix, _cast[i],
	           offset, deref, param;
	    }
	    if (genSpecRender) {
		printf ".Op %s %s\n", param, _proto[i];
	    }
	    if (genSpecSingle || genSpecVendpriv) {
		printf ".Pa %s %s\n", param, _proto[i];
	    }
	    if (genEncode) {
                printf "    \\paramline{%d}{\\glp{%s}}{%s}\n",
                    _xfer_size[i], _proto[i], param;
	    }
	    offset += xfer_size[_wire[i]];
	}
    }

    #
    # Pad scalars so that arrays will start on a 32-bit boundary.
    # But only need to push the PC here if another param follows, because
    # __GLX_END will reset it for the next command.
    #
    if (padInFixParams > 0) {
	offset += padInFixParams;
	if (genEncode) {
            printf "    \\paramline{%d}{}{unused}\n", padInFixParams;
	}
    }

    #
    # Write variable-sized arrays.
    #
    offsetString = offset;
    for (j=1; j <= numInVarParams; j++) {
	i = sortedInVarParams[j];
	param = paramName[i];
	if (genTrans) {
	    printf "\t%s_PUT_%s_ARRAY(%s,%s,%s);\n", shortMacroPrefix,
		_cast[i], offsetString, param, arrayCount[i];
	}
	if (genSpecRender) {
	    printf ".Op %s LISTof%s\n", param, _proto[i];
	}
	if (genSpecSingle || genSpecVendpriv) {
	    printf ".Pa %s LISTof%s\n", param, _proto[i];
	}
	if (genEncode) {
            printf "    \\paramline{%s}{\\glp{LISTof%s}}{%s}\n",
                arrayBytes[i], _proto[i], param;
	}
	offsetString = offsetString "+" arrayBytes[i];
    }

    if (genSpecRender) {
    	if (numInFixParams == 0 && numInVarParams == 0) {
        printf ".ti 0.5i\n";
    	    printf "\\fINo parameters.\\fP\n";
    	}
    }

    if (hasReturn || (numOutFixParams + numOutVarParams) > 0) {
    	if (genEncodeSingle || genEncodeVendpriv) {
            # printf "\\St\n";
            printf "\\replyarrow\n";
            printf "    \\paramline{1}{1}{Reply}\n";
            printf "    \\paramline{1}{}{unused}\n";
            printf "    \\paramline{2}{\\glp{CARD16}}{sequence number}\n";
	    read_return_data();
    	}
	if (genSpecSingle || genSpecVendpriv) {
	    printf ".Re\n";
	    read_return_data();
	}
    }

    #
    #  Finish writing the parameters; get the return data if needed.
    #
    if (genTransSingle || genTransVendpriv) {
	read_return_data();
	printf "\t%s_END();\n", macroPrefix;
    } else if (genTransDraw) {
	if (numInVarParams > 0) {
	    # The command size will be computed at runtime.
	    printf "\t%s_END(cmdlen);\n", macroPrefix;
	} else {
	    # The command size is a constant.
	    printf "\t%s_END(%s);\n", macroPrefix, cmdlen;
	}
    }

    #
    # Return a return value if needed.
    #
    if (hasReturn && genTrans) {
	printf "\treturn retval;\n";
    }

    if (genTrans) printf "}\n\n";
    if (genSpecRender) printf ".sp\n\n";
    if (genSpecSingle || genSpecVendpriv) printf ".Fe\n\n";
    if (genEncodeRender) printf "\\Ef\n";
    if (genEncodeSingle || genEncodeVendpriv) printf "\\Ef\n";

}

##############################################################################
#
# Compute symbolic reply length and pad size in units of 32 bit words.
# This is used in read_return_data() below.
#
##############################################################################
function build_reply_pad(xfer_size) {
    padSize = sprintf("n*%d", xfer_size);
    if (xfer_size == 1) {
        replyLength = sprintf("(n+p)/4");
        padSize = "n";
    } else if (xfer_size == 2) {
        replyLength = sprintf("(n*2+p)/4");
    } else if (xfer_size == 4) {
        replyLength = sprintf("n");
    } else if (xfer_size == 8) {
        replyLength = sprintf("n*2");
    } else {
        replyLength = sprintf("(n*%d+p)/4", xfer_size[i]);
    }
}

##############################################################################
#
# Read a reply packet and return the data back in the parameters.
#
##############################################################################
function read_return_data() {

    if (hasReturn || (numOutFixParams + numOutVarParams) > 0) {
        if (genTrans) {
	    printf "\t%s_READ_XREPLY();\n", macroPrefix;
	}
    } else {
        return;
    }

    #
    # Get the return value, if any.
    #
    if (hasReturn) {
	wireReturn = wiretype[returnUnmappedType];
	if (genTrans) {
	    printf "\t%s_GET_RETVAL(retval, GL%s);\n", macroPrefix,
	  	wiretype[returnUnmappedType];
	}
	#
	# Return types for the few routines that have them are 4 bytes large,
	# and the type must be defined in protoReturn.
	#
        # XXX Are return types different for Single and Vendpriv?
	if (genEncodeSingle || genEncodeVendpriv) {
	    if (!(wireReturn in protoReturn)) {
		specError("No protocol return type defined for " \
			wireReturn " in " functionName);
	    }
            # Only generate the return value here if there
            #   are no output parameters.
            if (!numOutFixParams && !numOutVarParams) {
		printf "    \\paramline{4}{0}{reply length}\n";
		printf "    \\paramline{4}{\\glp{%s}}{return value}\n",
		    protoReturn[wireReturn];
		printf "    \\paramline{20}{}{unused}\n";
	    }
        }
	if (genSpecSingle || genSpecVendpriv) {
	    if (!(wireReturn in protoReturn)) {
		specError("No protocol return type defined for " \
			wireReturn " in " functionName);
	    }
	    printf ".Pa return_value %s\n", protoReturn[wireReturn];
	}
    }

    #
    # Get computed size of a returned array, if any.
    #
    if (hasOutCompSizeParam) {
	if (genTrans) printf "\t%s_GET_SIZE(compsize);\n", macroPrefix;
    }
     
    #
    # Note that there is no skipping over padding, because so far gl.spec
    # contains only routines with either all fixed size return values, or one
    # variable-size returned array.
    #

    if (!numOutFixParams && !numOutVarParams) return;

    if (numOutCompSizeParams > 0) {
	i = sortedOutVarParams[1];
	param = paramName[i];
	if (genTrans) {
    	    printf "\tif (compsize == 1) {\n"; 
	    printf "\t    %s_GET_%s(%s);\n", macroPrefix, _cast[i], param;
	    printf "\t} else {\n";
	    printf "\t    %s_GET_%s_ARRAY(%s,%s);\n", macroPrefix, 
		_cast[i], param, arrayCount[i];
	    printf "\t}\n";
	}
	if (genEncodeSingle || genEncodeVendpriv) {
            build_reply_pad(_xfer_size[i]);
            printf "    \\paramline{4}{m}{reply length, m = (n==1 ? 0 : %s)}\n",
                replyLength;
            if (!hasReturn) {
		printf "    \\paramline{4}{}{unused}\n";
            } else {
                printf "    \\paramline{4}{\\glp{%s}}{return value}\n",
                    protoReturn[wireReturn];
            }
            printf "    \\paramline{4}{\\glp{CARD32}}{n}\n";
            printf "    \\\\ \n";
            printf "    \\Etext{if (n=1) this follows:}\n";
            printf "    \\\\ \n";
            printf "    \\paramline{%d}{\\glp{%s}}{%s}\n",
                _xfer_size[i], _proto[i], param;
            printf "    \\paramline{%d}{}{unused}\n\n",
                16 - _xfer_size[i];
            printf "    \\\\ \n";
            printf "    \\Etext{otherwise this follows:}\n";
            printf "    \\\\ \n";
            printf "    \\paramline{16}{}{unused}\n";
            printf "    \\paramline{n*%d}{\\glp{LISTof%s}}{%s}\n",
                _xfer_size[i], _proto[i], param;
	    if (_xfer_size[i] < 4) {
                printf "    \\paramline{p}{}{unused, p=pad(%s)}\n", padSize;
	    }
            printf "    \\\\ \n";
            printf "    \\Etext{%s}\n", \
 	       "Note that n may be zero, indicating that a GL error occurred.";
	}
	if (genSpecSingle || genSpecVendpriv) {
	    printf ".Pa %s LISTof%s\n", param, _proto[i];
	}

    } else {
	if (numOutFixParams > 0) {
	    i = sortedOutFixParams[1];
	    if (!isArray[i]) {
		#
		# There are no such functions in the GL API yet.
		#
		specError("Script is not ready for returned scalars:" \
			paramName[i] " in function " functionName);
	    }
	} else if (numOutVarParams > 0) {
	    i = sortedOutVarParams[1];
	}
	param = paramName[i];
	if (genTrans) {
	    printf "\t%s_GET_%s_ARRAY(%s,%s);\n", macroPrefix, _cast[i],
		param, arrayCount[i];
	}
	if (genEncodeSingle || genEncodeVendpriv) {
            # Can't compute reply len/pad numerically. If we could:
            #   pad = 3 - ((arrayCount[i]*_xfer_size[i] + 3) % 4);
            #   replyLength = arrayCount[i]*_xfer_size[i]+pad;

            build_reply_pad(_xfer_size[i]);

            printf "    \\paramline{4}{%s}{reply length}\n",
                replyLength;
            if (!hasReturn) {
		printf "    \\paramline{24}{}{unused}\n";
            } else {
                printf "    \\paramline{4}{\\glp{%s}}{return value}\n",
                    protoReturn[wireReturn];
                printf "    \\paramline{20}{}{unused}\n";
            }
            printf "    \\paramline{%s*%d}{\\glp{LISTof%s}}{%s}\n",
		arrayCount[i], _xfer_size[i], _proto[i], param;
            if (_xfer_size[i] < 4) {
                printf "    \\paramline{p}{}{unused, p=pad(%s)}\n", padSize;
	    }
	}
	if (genSpecSingle || genSpecVendpriv) {
	    printf ".Pa %s LISTof%s\n", param, _proto[i];
	}
    }
}


function finalize()
{
}