home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkConfig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  26.7 KB  |  991 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkConfig.c --
  3.  *
  4.  *    This file contains the Tk_ConfigureWidget procedure.
  5.  *
  6.  * Copyright (c) 1990-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkConfig.c 1.53 96/04/26 10:29:31
  13.  */
  14.  
  15. #include "tkPort.h"
  16. #include "tk.h"
  17.  
  18. /*
  19.  * Values for "flags" field of Tk_ConfigSpec structures.  Be sure
  20.  * to coordinate these values with those defined in tk.h
  21.  * (TK_CONFIG_COLOR_ONLY, etc.).  There must not be overlap!
  22.  *
  23.  * INIT -        Non-zero means (char *) things have been
  24.  *            converted to Tk_Uid's.
  25.  */
  26.  
  27. #define INIT        0x20
  28.  
  29. /*
  30.  * Forward declarations for procedures defined later in this file:
  31.  */
  32.  
  33. static int        DoConfig _ANSI_ARGS_((Tcl_Interp *interp,
  34.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  35.                 Tk_Uid value, int valueIsUid, char *widgRec));
  36. static Tk_ConfigSpec *    FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp,
  37.                 Tk_ConfigSpec *specs, char *argvName,
  38.                 int needFlags, int hateFlags));
  39. static char *        FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp,
  40.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  41.                 char *widgRec));
  42. static char *        FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp,
  43.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  44.                 char *widgRec, char *buffer,
  45.                 Tcl_FreeProc **freeProcPtr));
  46.  
  47. /*
  48.  *--------------------------------------------------------------
  49.  *
  50.  * Tk_ConfigureWidget --
  51.  *
  52.  *    Process command-line options and database options to
  53.  *    fill in fields of a widget record with resources and
  54.  *    other parameters.
  55.  *
  56.  * Results:
  57.  *    A standard Tcl return value.  In case of an error,
  58.  *    interp->result will hold an error message.
  59.  *
  60.  * Side effects:
  61.  *    The fields of widgRec get filled in with information
  62.  *    from argc/argv and the option database.  Old information
  63.  *    in widgRec's fields gets recycled.
  64.  *
  65.  *--------------------------------------------------------------
  66.  */
  67.  
  68. int
  69. Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags)
  70.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  71.     Tk_Window tkwin;        /* Window containing widget (needed to
  72.                  * set up X resources). */
  73.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  74.     int argc;            /* Number of elements in argv. */
  75.     char **argv;        /* Command-line options. */
  76.     char *widgRec;        /* Record whose fields are to be
  77.                  * modified.  Values must be properly
  78.                  * initialized. */
  79.     int flags;            /* Used to specify additional flags
  80.                  * that must be present in config specs
  81.                  * for them to be considered.  Also,
  82.                  * may have TK_CONFIG_ARGV_ONLY set. */
  83. {
  84.     register Tk_ConfigSpec *specPtr;
  85.     Tk_Uid value;        /* Value of option from database. */
  86.     int needFlags;        /* Specs must contain this set of flags
  87.                  * or else they are not considered. */
  88.     int hateFlags;        /* If a spec contains any bits here, it's
  89.                  * not considered. */
  90.  
  91.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  92.     if (Tk_Depth(tkwin) <= 1) {
  93.     hateFlags = TK_CONFIG_COLOR_ONLY;
  94.     } else {
  95.     hateFlags = TK_CONFIG_MONO_ONLY;
  96.     }
  97.  
  98.     /*
  99.      * Pass one:  scan through all the option specs, replacing strings
  100.      * with Tk_Uids (if this hasn't been done already) and clearing
  101.      * the TK_CONFIG_OPTION_SPECIFIED flags.
  102.      */
  103.  
  104.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  105.     if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) {
  106.         if (specPtr->dbName != NULL) {
  107.         specPtr->dbName = Tk_GetUid(specPtr->dbName);
  108.         }
  109.         if (specPtr->dbClass != NULL) {
  110.         specPtr->dbClass = Tk_GetUid(specPtr->dbClass);
  111.         }
  112.         if (specPtr->defValue != NULL) {
  113.         specPtr->defValue = Tk_GetUid(specPtr->defValue);
  114.         }
  115.     }
  116.     specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED)
  117.         | INIT;
  118.     }
  119.  
  120.     /*
  121.      * Pass two:  scan through all of the arguments, processing those
  122.      * that match entries in the specs.
  123.      */
  124.  
  125.     for ( ; argc > 0; argc -= 2, argv += 2) {
  126.     specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags);
  127.     if (specPtr == NULL) {
  128.         return TCL_ERROR;
  129.     }
  130.  
  131.     /*
  132.      * Process the entry.
  133.      */
  134.  
  135.     if (argc < 2) {
  136.         Tcl_AppendResult(interp, "value for \"", *argv,
  137.             "\" missing", (char *) NULL);
  138.         return TCL_ERROR;
  139.     }
  140.     if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) {
  141.         char msg[100];
  142.  
  143.         sprintf(msg, "\n    (processing \"%.40s\" option)",
  144.             specPtr->argvName);
  145.         Tcl_AddErrorInfo(interp, msg);
  146.         return TCL_ERROR;
  147.     }
  148.     specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
  149.     }
  150.  
  151.     /*
  152.      * Pass three:  scan through all of the specs again;  if no
  153.      * command-line argument matched a spec, then check for info
  154.      * in the option database.  If there was nothing in the
  155.      * database, then use the default.
  156.      */
  157.  
  158.     if (!(flags & TK_CONFIG_ARGV_ONLY)) {
  159.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  160.         if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
  161.             || (specPtr->argvName == NULL)
  162.             || (specPtr->type == TK_CONFIG_SYNONYM)) {
  163.         continue;
  164.         }
  165.         if (((specPtr->specFlags & needFlags) != needFlags)
  166.             || (specPtr->specFlags & hateFlags)) {
  167.         continue;
  168.         }
  169.         value = NULL;
  170.         if (specPtr->dbName != NULL) {
  171.         value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass);
  172.         }
  173.         if (value != NULL) {
  174.         if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  175.             TCL_OK) {
  176.             char msg[200];
  177.     
  178.             sprintf(msg, "\n    (%s \"%.50s\" in widget \"%.50s\")",
  179.                 "database entry for",
  180.                 specPtr->dbName, Tk_PathName(tkwin));
  181.             Tcl_AddErrorInfo(interp, msg);
  182.             return TCL_ERROR;
  183.         }
  184.         } else {
  185.         value = specPtr->defValue;
  186.         if ((value != NULL) && !(specPtr->specFlags
  187.             & TK_CONFIG_DONT_SET_DEFAULT)) {
  188.             if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  189.                 TCL_OK) {
  190.             char msg[200];
  191.     
  192.             sprintf(msg,
  193.                 "\n    (%s \"%.50s\" in widget \"%.50s\")",
  194.                 "default value for",
  195.                 specPtr->dbName, Tk_PathName(tkwin));
  196.             Tcl_AddErrorInfo(interp, msg);
  197.             return TCL_ERROR;
  198.             }
  199.         }
  200.         }
  201.     }
  202.     }
  203.  
  204.     return TCL_OK;
  205. }
  206.  
  207. /*
  208.  *--------------------------------------------------------------
  209.  *
  210.  * FindConfigSpec --
  211.  *
  212.  *    Search through a table of configuration specs, looking for
  213.  *    one that matches a given argvName.
  214.  *
  215.  * Results:
  216.  *    The return value is a pointer to the matching entry, or NULL
  217.  *    if nothing matched.  In that case an error message is left
  218.  *    in interp->result.
  219.  *
  220.  * Side effects:
  221.  *    None.
  222.  *
  223.  *--------------------------------------------------------------
  224.  */
  225.  
  226. static Tk_ConfigSpec *
  227. FindConfigSpec(interp, specs, argvName, needFlags, hateFlags)
  228.     Tcl_Interp *interp;        /* Used for reporting errors. */
  229.     Tk_ConfigSpec *specs;    /* Pointer to table of configuration
  230.                  * specifications for a widget. */
  231.     char *argvName;        /* Name (suitable for use in a "config"
  232.                  * command) identifying particular option. */
  233.     int needFlags;        /* Flags that must be present in matching
  234.                  * entry. */
  235.     int hateFlags;        /* Flags that must NOT be present in
  236.                  * matching entry. */
  237. {
  238.     register Tk_ConfigSpec *specPtr;
  239.     register char c;        /* First character of current argument. */
  240.     Tk_ConfigSpec *matchPtr;    /* Matching spec, or NULL. */
  241.     size_t length;
  242.  
  243.     c = argvName[1];
  244.     length = strlen(argvName);
  245.     matchPtr = NULL;
  246.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  247.     if (specPtr->argvName == NULL) {
  248.         continue;
  249.     }
  250.     if ((specPtr->argvName[1] != c)
  251.         || (strncmp(specPtr->argvName, argvName, length) != 0)) {
  252.         continue;
  253.     }
  254.     if (((specPtr->specFlags & needFlags) != needFlags)
  255.         || (specPtr->specFlags & hateFlags)) {
  256.         continue;
  257.     }
  258.     if (specPtr->argvName[length] == 0) {
  259.         matchPtr = specPtr;
  260.         goto gotMatch;
  261.     }
  262.     if (matchPtr != NULL) {
  263.         Tcl_AppendResult(interp, "ambiguous option \"", argvName,
  264.             "\"", (char *) NULL);
  265.         return (Tk_ConfigSpec *) NULL;
  266.     }
  267.     matchPtr = specPtr;
  268.     }
  269.  
  270.     if (matchPtr == NULL) {
  271.     Tcl_AppendResult(interp, "unknown option \"", argvName,
  272.         "\"", (char *) NULL);
  273.     return (Tk_ConfigSpec *) NULL;
  274.     }
  275.  
  276.     /*
  277.      * Found a matching entry.  If it's a synonym, then find the
  278.      * entry that it's a synonym for.
  279.      */
  280.  
  281.     gotMatch:
  282.     specPtr = matchPtr;
  283.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  284.     for (specPtr = specs; ; specPtr++) {
  285.         if (specPtr->type == TK_CONFIG_END) {
  286.         Tcl_AppendResult(interp,
  287.             "couldn't find synonym for option \"",
  288.             argvName, "\"", (char *) NULL);
  289.         return (Tk_ConfigSpec *) NULL;
  290.         }
  291.         if ((specPtr->dbName == matchPtr->dbName) 
  292.             && (specPtr->type != TK_CONFIG_SYNONYM)
  293.             && ((specPtr->specFlags & needFlags) == needFlags)
  294.             && !(specPtr->specFlags & hateFlags)) {
  295.         break;
  296.         }
  297.     }
  298.     }
  299.     return specPtr;
  300. }
  301.  
  302. /*
  303.  *--------------------------------------------------------------
  304.  *
  305.  * DoConfig --
  306.  *
  307.  *    This procedure applies a single configuration option
  308.  *    to a widget record.
  309.  *
  310.  * Results:
  311.  *    A standard Tcl return value.
  312.  *
  313.  * Side effects:
  314.  *    WidgRec is modified as indicated by specPtr and value.
  315.  *    The old value is recycled, if that is appropriate for
  316.  *    the value type.
  317.  *
  318.  *--------------------------------------------------------------
  319.  */
  320.  
  321. static int
  322. DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec)
  323.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  324.     Tk_Window tkwin;        /* Window containing widget (needed to
  325.                  * set up X resources). */
  326.     Tk_ConfigSpec *specPtr;    /* Specifier to apply. */
  327.     char *value;        /* Value to use to fill in widgRec. */
  328.     int valueIsUid;        /* Non-zero means value is a Tk_Uid;
  329.                  * zero means it's an ordinary string. */
  330.     char *widgRec;        /* Record whose fields are to be
  331.                  * modified.  Values must be properly
  332.                  * initialized. */
  333. {
  334.     char *ptr;
  335.     Tk_Uid uid;
  336.     int nullValue;
  337.  
  338.     nullValue = 0;
  339.     if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) {
  340.     nullValue = 1;
  341.     }
  342.  
  343.     do {
  344.     ptr = widgRec + specPtr->offset;
  345.     switch (specPtr->type) {
  346.         case TK_CONFIG_BOOLEAN:
  347.         if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) {
  348.             return TCL_ERROR;
  349.         }
  350.         break;
  351.         case TK_CONFIG_INT:
  352.         if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) {
  353.             return TCL_ERROR;
  354.         }
  355.         break;
  356.         case TK_CONFIG_DOUBLE:
  357.         if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) {
  358.             return TCL_ERROR;
  359.         }
  360.         break;
  361.         case TK_CONFIG_STRING: {
  362.         char *old, *new;
  363.  
  364.         if (nullValue) {
  365.             new = NULL;
  366.         } else {
  367.             new = (char *) ckalloc((unsigned) (strlen(value) + 1));
  368.             strcpy(new, value);
  369.         }
  370.         old = *((char **) ptr);
  371.         if (old != NULL) {
  372.             ckfree(old);
  373.         }
  374.         *((char **) ptr) = new;
  375.         break;
  376.         }
  377.         case TK_CONFIG_UID:
  378.         if (nullValue) {
  379.             *((Tk_Uid *) ptr) = NULL;
  380.         } else {
  381.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  382.             *((Tk_Uid *) ptr) = uid;
  383.         }
  384.         break;
  385.         case TK_CONFIG_COLOR: {
  386.         XColor *newPtr, *oldPtr;
  387.  
  388.         if (nullValue) {
  389.             newPtr = NULL;
  390.         } else {
  391.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  392.             newPtr = Tk_GetColor(interp, tkwin, uid);
  393.             if (newPtr == NULL) {
  394.             return TCL_ERROR;
  395.             }
  396.         }
  397.         oldPtr = *((XColor **) ptr);
  398.         if (oldPtr != NULL) {
  399.             Tk_FreeColor(oldPtr);
  400.         }
  401.         *((XColor **) ptr) = newPtr;
  402.         break;
  403.         }
  404.         case TK_CONFIG_FONT: {
  405.         Tk_Font new;
  406.  
  407.         if (nullValue) {
  408.             new = NULL;
  409.         } else {
  410.             new = Tk_GetFont(interp, tkwin, value);
  411.             if (new == NULL) {
  412.             return TCL_ERROR;
  413.             }
  414.         }
  415.         Tk_FreeFont(*((Tk_Font *) ptr));
  416.         *((Tk_Font *) ptr) = new;
  417.         break;
  418.         }
  419.         case TK_CONFIG_BITMAP: {
  420.         Pixmap new, old;
  421.  
  422.         if (nullValue) {
  423.             new = None;
  424.             } else {
  425.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  426.             new = Tk_GetBitmap(interp, tkwin, uid);
  427.             if (new == None) {
  428.             return TCL_ERROR;
  429.             }
  430.         }
  431.         old = *((Pixmap *) ptr);
  432.         if (old != None) {
  433.             Tk_FreeBitmap(Tk_Display(tkwin), old);
  434.         }
  435.         *((Pixmap *) ptr) = new;
  436.         break;
  437.         }
  438.         case TK_CONFIG_BORDER: {
  439.         Tk_3DBorder new, old;
  440.  
  441.         if (nullValue) {
  442.             new = NULL;
  443.         } else {
  444.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  445.             new = Tk_Get3DBorder(interp, tkwin, uid);
  446.             if (new == NULL) {
  447.             return TCL_ERROR;
  448.             }
  449.         }
  450.         old = *((Tk_3DBorder *) ptr);
  451.         if (old != NULL) {
  452.             Tk_Free3DBorder(old);
  453.         }
  454.         *((Tk_3DBorder *) ptr) = new;
  455.         break;
  456.         }
  457.         case TK_CONFIG_RELIEF:
  458.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  459.         if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) {
  460.             return TCL_ERROR;
  461.         }
  462.         break;
  463.         case TK_CONFIG_CURSOR:
  464.         case TK_CONFIG_ACTIVE_CURSOR: {
  465.         Tk_Cursor new, old;
  466.  
  467.         if (nullValue) {
  468.             new = None;
  469.         } else {
  470.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  471.             new = Tk_GetCursor(interp, tkwin, uid);
  472.             if (new == None) {
  473.             return TCL_ERROR;
  474.             }
  475.         }
  476.         old = *((Tk_Cursor *) ptr);
  477.         if (old != None) {
  478.             Tk_FreeCursor(Tk_Display(tkwin), old);
  479.         }
  480.         *((Tk_Cursor *) ptr) = new;
  481.         if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) {
  482.             Tk_DefineCursor(tkwin, new);
  483.         }
  484.         break;
  485.         }
  486.         case TK_CONFIG_JUSTIFY:
  487.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  488.         if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) {
  489.             return TCL_ERROR;
  490.         }
  491.         break;
  492.         case TK_CONFIG_ANCHOR:
  493.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  494.         if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) {
  495.             return TCL_ERROR;
  496.         }
  497.         break;
  498.         case TK_CONFIG_CAP_STYLE:
  499.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  500.         if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) {
  501.             return TCL_ERROR;
  502.         }
  503.         break;
  504.         case TK_CONFIG_JOIN_STYLE:
  505.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  506.         if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) {
  507.             return TCL_ERROR;
  508.         }
  509.         break;
  510.         case TK_CONFIG_PIXELS:
  511.         if (Tk_GetPixels(interp, tkwin, value, (int *) ptr)
  512.             != TCL_OK) {
  513.             return TCL_ERROR;
  514.         }
  515.         break;
  516.         case TK_CONFIG_MM:
  517.         if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr)
  518.             != TCL_OK) {
  519.             return TCL_ERROR;
  520.         }
  521.         break;
  522.         case TK_CONFIG_WINDOW: {
  523.         Tk_Window tkwin2;
  524.  
  525.         if (nullValue) {
  526.             tkwin2 = NULL;
  527.         } else {
  528.             tkwin2 = Tk_NameToWindow(interp, value, tkwin);
  529.             if (tkwin2 == NULL) {
  530.             return TCL_ERROR;
  531.             }
  532.         }
  533.         *((Tk_Window *) ptr) = tkwin2;
  534.         break;
  535.         }
  536.         case TK_CONFIG_CUSTOM:
  537.         if ((*specPtr->customPtr->parseProc)(
  538.             specPtr->customPtr->clientData, interp, tkwin,
  539.             value, widgRec, specPtr->offset) != TCL_OK) {
  540.             return TCL_ERROR;
  541.         }
  542.         break;
  543.         default: {
  544.         sprintf(interp->result, "bad config table: unknown type %d",
  545.             specPtr->type);
  546.         return TCL_ERROR;
  547.         }
  548.     }
  549.     specPtr++;
  550.     } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END));
  551.     return TCL_OK;
  552. }
  553.  
  554. /*
  555.  *--------------------------------------------------------------
  556.  *
  557.  * Tk_ConfigureInfo --
  558.  *
  559.  *    Return information about the configuration options
  560.  *    for a window, and their current values.
  561.  *
  562.  * Results:
  563.  *    Always returns TCL_OK.  Interp->result will be modified
  564.  *    hold a description of either a single configuration option
  565.  *    available for "widgRec" via "specs", or all the configuration
  566.  *    options available.  In the "all" case, the result will
  567.  *    available for "widgRec" via "specs".  The result will
  568.  *    be a list, each of whose entries describes one option.
  569.  *    Each entry will itself be a list containing the option's
  570.  *    name for use on command lines, database name, database
  571.  *    class, default value, and current value (empty string
  572.  *    if none).  For options that are synonyms, the list will
  573.  *    contain only two values:  name and synonym name.  If the
  574.  *    "name" argument is non-NULL, then the only information
  575.  *    returned is that for the named argument (i.e. the corresponding
  576.  *    entry in the overall list is returned).
  577.  *
  578.  * Side effects:
  579.  *    None.
  580.  *
  581.  *--------------------------------------------------------------
  582.  */
  583.  
  584. int
  585. Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags)
  586.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  587.     Tk_Window tkwin;        /* Window corresponding to widgRec. */
  588.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  589.     char *widgRec;        /* Record whose fields contain current
  590.                  * values for options. */
  591.     char *argvName;        /* If non-NULL, indicates a single option
  592.                  * whose info is to be returned.  Otherwise
  593.                  * info is returned for all options. */
  594.     int flags;            /* Used to specify additional flags
  595.                  * that must be present in config specs
  596.                  * for them to be considered. */
  597. {
  598.     register Tk_ConfigSpec *specPtr;
  599.     int needFlags, hateFlags;
  600.     char *list;
  601.     char *leader = "{";
  602.  
  603.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  604.     if (Tk_Depth(tkwin) <= 1) {
  605.     hateFlags = TK_CONFIG_COLOR_ONLY;
  606.     } else {
  607.     hateFlags = TK_CONFIG_MONO_ONLY;
  608.     }
  609.  
  610.     /*
  611.      * If information is only wanted for a single configuration
  612.      * spec, then handle that one spec specially.
  613.      */
  614.  
  615.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  616.     if (argvName != NULL) {
  617.     specPtr = FindConfigSpec(interp, specs, argvName, needFlags,
  618.         hateFlags);
  619.     if (specPtr == NULL) {
  620.         return TCL_ERROR;
  621.     }
  622.     interp->result = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
  623.     interp->freeProc = TCL_DYNAMIC;
  624.     return TCL_OK;
  625.     }
  626.  
  627.     /*
  628.      * Loop through all the specs, creating a big list with all
  629.      * their information.
  630.      */
  631.  
  632.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  633.     if ((argvName != NULL) && (specPtr->argvName != argvName)) {
  634.         continue;
  635.     }
  636.     if (((specPtr->specFlags & needFlags) != needFlags)
  637.         || (specPtr->specFlags & hateFlags)) {
  638.         continue;
  639.     }
  640.     if (specPtr->argvName == NULL) {
  641.         continue;
  642.     }
  643.     list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
  644.     Tcl_AppendResult(interp, leader, list, "}", (char *) NULL);
  645.     ckfree(list);
  646.     leader = " {";
  647.     }
  648.     return TCL_OK;
  649. }
  650.  
  651. /*
  652.  *--------------------------------------------------------------
  653.  *
  654.  * FormatConfigInfo --
  655.  *
  656.  *    Create a valid Tcl list holding the configuration information
  657.  *    for a single configuration option.
  658.  *
  659.  * Results:
  660.  *    A Tcl list, dynamically allocated.  The caller is expected to
  661.  *    arrange for this list to be freed eventually.
  662.  *
  663.  * Side effects:
  664.  *    Memory is allocated.
  665.  *
  666.  *--------------------------------------------------------------
  667.  */
  668.  
  669. static char *
  670. FormatConfigInfo(interp, tkwin, specPtr, widgRec)
  671.     Tcl_Interp *interp;            /* Interpreter to use for things
  672.                      * like floating-point precision. */
  673.     Tk_Window tkwin;            /* Window corresponding to widget. */
  674.     register Tk_ConfigSpec *specPtr;    /* Pointer to information describing
  675.                      * option. */
  676.     char *widgRec;            /* Pointer to record holding current
  677.                      * values of info for widget. */
  678. {
  679.     char *argv[6], *result;
  680.     char buffer[200];
  681.     Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL;
  682.  
  683.     argv[0] = specPtr->argvName;
  684.     argv[1] = specPtr->dbName;
  685.     argv[2] = specPtr->dbClass;
  686.     argv[3] = specPtr->defValue;
  687.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  688.     return Tcl_Merge(2, argv);
  689.     }
  690.     argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer,
  691.         &freeProc);
  692.     if (argv[1] == NULL) {
  693.     argv[1] = "";
  694.     }
  695.     if (argv[2] == NULL) {
  696.     argv[2] = "";
  697.     }
  698.     if (argv[3] == NULL) {
  699.     argv[3] = "";
  700.     }
  701.     if (argv[4] == NULL) {
  702.     argv[4] = "";
  703.     }
  704.     result = Tcl_Merge(5, argv);
  705.     if (freeProc != NULL) {
  706.     if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
  707.         ckfree(argv[4]);
  708.     } else {
  709.         (*freeProc)(argv[4]);
  710.     }
  711.     }
  712.     return result;
  713. }
  714.  
  715. /*
  716.  *----------------------------------------------------------------------
  717.  *
  718.  * FormatConfigValue --
  719.  *
  720.  *    This procedure formats the current value of a configuration
  721.  *    option.
  722.  *
  723.  * Results:
  724.  *    The return value is the formatted value of the option given
  725.  *    by specPtr and widgRec.  If the value is static, so that it
  726.  *    need not be freed, *freeProcPtr will be set to NULL;  otherwise
  727.  *    *freeProcPtr will be set to the address of a procedure to
  728.  *    free the result, and the caller must invoke this procedure
  729.  *    when it is finished with the result.
  730.  *
  731.  * Side effects:
  732.  *    None.
  733.  *
  734.  *----------------------------------------------------------------------
  735.  */
  736.  
  737. static char *
  738. FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr)
  739.     Tcl_Interp *interp;        /* Interpreter for use in real conversions. */
  740.     Tk_Window tkwin;        /* Window corresponding to widget. */
  741.     Tk_ConfigSpec *specPtr;    /* Pointer to information describing option.
  742.                  * Must not point to a synonym option. */
  743.     char *widgRec;        /* Pointer to record holding current
  744.                  * values of info for widget. */
  745.     char *buffer;        /* Static buffer to use for small values.
  746.                  * Must have at least 200 bytes of storage. */
  747.     Tcl_FreeProc **freeProcPtr;    /* Pointer to word to fill in with address
  748.                  * of procedure to free the result, or NULL
  749.                  * if result is static. */
  750. {
  751.     char *ptr, *result;
  752.  
  753.     *freeProcPtr = NULL;
  754.     ptr = widgRec + specPtr->offset;
  755.     result = "";
  756.     switch (specPtr->type) {
  757.     case TK_CONFIG_BOOLEAN:
  758.         if (*((int *) ptr) == 0) {
  759.         result = "0";
  760.         } else {
  761.         result = "1";
  762.         }
  763.         break;
  764.     case TK_CONFIG_INT:
  765.         sprintf(buffer, "%d", *((int *) ptr));
  766.         result = buffer;
  767.         break;
  768.     case TK_CONFIG_DOUBLE:
  769.         Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  770.         result = buffer;
  771.         break;
  772.     case TK_CONFIG_STRING:
  773.         result = (*(char **) ptr);
  774.         if (result == NULL) {
  775.         result = "";
  776.         }
  777.         break;
  778.     case TK_CONFIG_UID: {
  779.         Tk_Uid uid = *((Tk_Uid *) ptr);
  780.         if (uid != NULL) {
  781.         result = uid;
  782.         }
  783.         break;
  784.     }
  785.     case TK_CONFIG_COLOR: {
  786.         XColor *colorPtr = *((XColor **) ptr);
  787.         if (colorPtr != NULL) {
  788.         result = Tk_NameOfColor(colorPtr);
  789.         }
  790.         break;
  791.     }
  792.     case TK_CONFIG_FONT: {
  793.         Tk_Font tkfont = *((Tk_Font *) ptr);
  794.         if (tkfont != NULL) {
  795.         result = Tk_NameOfFont(tkfont);
  796.         }
  797.         break;
  798.     }
  799.     case TK_CONFIG_BITMAP: {
  800.         Pixmap pixmap = *((Pixmap *) ptr);
  801.         if (pixmap != None) {
  802.         result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap);
  803.         }
  804.         break;
  805.     }
  806.     case TK_CONFIG_BORDER: {
  807.         Tk_3DBorder border = *((Tk_3DBorder *) ptr);
  808.         if (border != NULL) {
  809.         result = Tk_NameOf3DBorder(border);
  810.         }
  811.         break;
  812.     }
  813.     case TK_CONFIG_RELIEF:
  814.         result = Tk_NameOfRelief(*((int *) ptr));
  815.         break;
  816.     case TK_CONFIG_CURSOR:
  817.     case TK_CONFIG_ACTIVE_CURSOR: {
  818.         Tk_Cursor cursor = *((Tk_Cursor *) ptr);
  819.         if (cursor != None) {
  820.         result = Tk_NameOfCursor(Tk_Display(tkwin), cursor);
  821.         }
  822.         break;
  823.     }
  824.     case TK_CONFIG_JUSTIFY:
  825.         result = Tk_NameOfJustify(*((Tk_Justify *) ptr));
  826.         break;
  827.     case TK_CONFIG_ANCHOR:
  828.         result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr));
  829.         break;
  830.     case TK_CONFIG_CAP_STYLE:
  831.         result = Tk_NameOfCapStyle(*((int *) ptr));
  832.         break;
  833.     case TK_CONFIG_JOIN_STYLE:
  834.         result = Tk_NameOfJoinStyle(*((int *) ptr));
  835.         break;
  836.     case TK_CONFIG_PIXELS:
  837.         sprintf(buffer, "%d", *((int *) ptr));
  838.         result = buffer;
  839.         break;
  840.     case TK_CONFIG_MM:
  841.         Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  842.         result = buffer;
  843.         break;
  844.     case TK_CONFIG_WINDOW: {
  845.         Tk_Window tkwin;
  846.  
  847.         tkwin = *((Tk_Window *) ptr);
  848.         if (tkwin != NULL) {
  849.         result = Tk_PathName(tkwin);
  850.         }
  851.         break;
  852.     }
  853.     case TK_CONFIG_CUSTOM:
  854.         result = (*specPtr->customPtr->printProc)(
  855.             specPtr->customPtr->clientData, tkwin, widgRec,
  856.             specPtr->offset, freeProcPtr);
  857.         break;
  858.     default: 
  859.         result = "?? unknown type ??";
  860.     }
  861.     return result;
  862. }
  863.  
  864. /*
  865.  *----------------------------------------------------------------------
  866.  *
  867.  * Tk_ConfigureValue --
  868.  *
  869.  *    This procedure returns the current value of a configuration
  870.  *    option for a widget.
  871.  *
  872.  * Results:
  873.  *    The return value is a standard Tcl completion code (TCL_OK or
  874.  *    TCL_ERROR).  Interp->result will be set to hold either the value
  875.  *    of the option given by argvName (if TCL_OK is returned) or
  876.  *    an error message (if TCL_ERROR is returned).
  877.  *
  878.  * Side effects:
  879.  *    None.
  880.  *
  881.  *----------------------------------------------------------------------
  882.  */
  883.  
  884. int
  885. Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags)
  886.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  887.     Tk_Window tkwin;        /* Window corresponding to widgRec. */
  888.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  889.     char *widgRec;        /* Record whose fields contain current
  890.                  * values for options. */
  891.     char *argvName;        /* Gives the command-line name for the
  892.                  * option whose value is to be returned. */
  893.     int flags;            /* Used to specify additional flags
  894.                  * that must be present in config specs
  895.                  * for them to be considered. */
  896. {
  897.     Tk_ConfigSpec *specPtr;
  898.     int needFlags, hateFlags;
  899.  
  900.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  901.     if (Tk_Depth(tkwin) <= 1) {
  902.     hateFlags = TK_CONFIG_COLOR_ONLY;
  903.     } else {
  904.     hateFlags = TK_CONFIG_MONO_ONLY;
  905.     }
  906.     specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags);
  907.     if (specPtr == NULL) {
  908.     return TCL_ERROR;
  909.     }
  910.     interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec,
  911.         interp->result, &interp->freeProc);
  912.     return TCL_OK;
  913. }
  914.  
  915. /*
  916.  *----------------------------------------------------------------------
  917.  *
  918.  * Tk_FreeOptions --
  919.  *
  920.  *    Free up all resources associated with configuration options.
  921.  *
  922.  * Results:
  923.  *    None.
  924.  *
  925.  * Side effects:
  926.  *    Any resource in widgRec that is controlled by a configuration
  927.  *    option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate
  928.  *    fashion.
  929.  *
  930.  *----------------------------------------------------------------------
  931.  */
  932.  
  933.     /* ARGSUSED */
  934. void
  935. Tk_FreeOptions(specs, widgRec, display, needFlags)
  936.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  937.     char *widgRec;        /* Record whose fields contain current
  938.                  * values for options. */
  939.     Display *display;        /* X display; needed for freeing some
  940.                  * resources. */
  941.     int needFlags;        /* Used to specify additional flags
  942.                  * that must be present in config specs
  943.                  * for them to be considered. */
  944. {
  945.     register Tk_ConfigSpec *specPtr;
  946.     char *ptr;
  947.  
  948.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  949.     if ((specPtr->specFlags & needFlags) != needFlags) {
  950.         continue;
  951.     }
  952.     ptr = widgRec + specPtr->offset;
  953.     switch (specPtr->type) {
  954.         case TK_CONFIG_STRING:
  955.         if (*((char **) ptr) != NULL) {
  956.             ckfree(*((char **) ptr));
  957.             *((char **) ptr) = NULL;
  958.         }
  959.         break;
  960.         case TK_CONFIG_COLOR:
  961.         if (*((XColor **) ptr) != NULL) {
  962.             Tk_FreeColor(*((XColor **) ptr));
  963.             *((XColor **) ptr) = NULL;
  964.         }
  965.         break;
  966.         case TK_CONFIG_FONT:
  967.         Tk_FreeFont(*((Tk_Font *) ptr));
  968.         *((Tk_Font *) ptr) = NULL;
  969.         break;
  970.         case TK_CONFIG_BITMAP:
  971.         if (*((Pixmap *) ptr) != None) {
  972.             Tk_FreeBitmap(display, *((Pixmap *) ptr));
  973.             *((Pixmap *) ptr) = None;
  974.         }
  975.         break;
  976.         case TK_CONFIG_BORDER:
  977.         if (*((Tk_3DBorder *) ptr) != NULL) {
  978.             Tk_Free3DBorder(*((Tk_3DBorder *) ptr));
  979.             *((Tk_3DBorder *) ptr) = NULL;
  980.         }
  981.         break;
  982.         case TK_CONFIG_CURSOR:
  983.         case TK_CONFIG_ACTIVE_CURSOR:
  984.         if (*((Tk_Cursor *) ptr) != None) {
  985.             Tk_FreeCursor(display, *((Tk_Cursor *) ptr));
  986.             *((Tk_Cursor *) ptr) = None;
  987.         }
  988.     }
  989.     }
  990. }
  991.