home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / plplot / plplot_2 / src / tcl / tclMatrix. < prev   
Encoding:
Text File  |  1994-08-09  |  17.3 KB  |  663 lines

  1. /* $Id: tclMatrix.c,v 1.6 1994/08/09 08:33:35 mjl Exp $
  2.  * $Log: tclMatrix.c,v $
  3.  * Revision 1.6  1994/08/09  08:33:35  mjl
  4.  * Changed the tclMatrix API once again.  The 'matrix' operator now sets up a
  5.  * command for the actual name used to declare the matrix.  This is faster
  6.  * than the old way, more intuitive, and less robust (the created matrix is
  7.  * global).  The last problem can presumably fixed by modifications to the
  8.  * Tcl kernel to support a matrix type, and is worth sacrificing for now
  9.  * in favor of a better syntax.  The matrix declarator sets a local variable
  10.  * of the same name as the created (matrix) command in order to automatically
  11.  * free locally-declared matrix resources at the end of a proc.  So previous
  12.  * scripts will still work.
  13.  *
  14.  * Revision 1.5  1994/06/30  18:55:02  mjl
  15.  * Now accepts an initializer when matrix is declared, for example:
  16.  * matrix base i 4 = {0, 200, 500, 600}.  Only works for 1-d arrays so far.
  17.  *
  18.  * Revision 1.4  1994/06/30  05:45:24  furnish
  19.  * Cobbled together an extension facility which allows a user to define
  20.  * their own subcommands for tclMatricies.  The idea is that you can use
  21.  * this to implement your own matrix processing commands entirely on the
  22.  * compiled side.  fft's, matrix multiplication, inversion, etc.
  23.  *
  24.  * Revision 1.3  1994/06/25  20:38:59  mjl
  25.  * Added support for integer matrix data.  Substantially rewrote and improved
  26.  * code in the process.  Extension to handle other types or higher
  27.  * dimensionality arrays should now be straightforward.
  28.  *
  29.  * Revision 1.2  1994/06/24  20:38:23  mjl
  30.  * Changed name of struct to tclMatrix to avoid conflicts with C++ Matrix
  31.  * classes.
  32.  *
  33.  * Revision 1.1  1994/06/23  22:42:53  mjl
  34.  * The Tcl Matrix class moved here, since it is useful independent of the
  35.  * Tk driver.
  36.  *
  37.  * Revision 1.2  1994/06/16  21:55:54  mjl
  38.  * Changed to new declaration syntax.  Now declaration must specify variable
  39.  * that holds matrix operator name.  This allows matrix command to place a
  40.  * trace on any unset of the variable, in which case it can clean up after
  41.  * itself.  I.e. when a matrix is declared locally, it goes away
  42.  * automatically when the proc exits (note to itcl users: since itcl does not
  43.  * let you place traces on class data, you will need to either make it global
  44.  * or create a destructor for it).
  45.  *
  46.  * Revision 1.1  1994/06/16  19:28:35  mjl
  47.  * New Tcl matrix command.  Supplies a much-needed new capability to Tcl.
  48.  * Arrays are stored as binary, column-dominant, and contiguous, so that
  49.  * interaction with scientific code API's as well as Tcl is trivial.
  50.  */
  51.  
  52. /*----------------------------------------------------------------------*\
  53.  *
  54.  * tclMatrix.c --
  55.  *
  56.  *    This file contains routines that implement Tcl matrices.
  57.  *    These are operators that are used to store, return, and modify
  58.  *    numeric data stored in binary array format.  The emphasis is
  59.  *    on high performance and low overhead, something that Tcl lists
  60.  *    or associative arrays aren't so good at.
  61.  *
  62.  * Maurice LeBrun
  63.  * IFS, University of Texas at Austin
  64.  * 10-Jun-1994
  65. \*----------------------------------------------------------------------*/
  66.  
  67. /*
  68. #define DEBUG
  69. */
  70.  
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <tcl.h>
  74. #include "tclMatrix.h"
  75.  
  76. /* Internal data */
  77.  
  78. static int matNum;        /* Counter used in simple naming scheme */
  79. static int matTable_initted;    /* Hash table initialization flag */
  80. static Tcl_HashTable matTable;    /* Hash table for external access to data */
  81.  
  82. /* Function prototypes */
  83.  
  84. /* Invoked to process the "matrix" Tcl command. */
  85.  
  86. static  int
  87. MatrixCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
  88.  
  89. /* Causes matrix command to be deleted.  */
  90.  
  91. static char *
  92. DeleteMatrixVar(ClientData clientData,
  93.         Tcl_Interp *interp, char *name1, char *name2, int flags);
  94.  
  95. /* Releases all the resources allocated to the matrix command. */
  96.  
  97. static void
  98. DeleteMatrixCmd(ClientData clientData);
  99.  
  100. /* These do the put/get operations for each supported type */
  101.  
  102. static void
  103. MatrixPut_f(ClientData clientData, int index, char *string);
  104.  
  105. static void
  106. MatrixGet_f(ClientData clientData, int index, char *string);
  107.  
  108. static void
  109. MatrixPut_i(ClientData clientData, int index, char *string);
  110.  
  111. static void
  112. MatrixGet_i(ClientData clientData, int index, char *string);
  113.  
  114. /*----------------------------------------------------------------------*\
  115.  *
  116.  * Tcl_MatCmd --
  117.  *
  118.  *    Invoked to process the "matrix" Tcl command.
  119.  *    Creates a multiply dimensioned array (matrix) of floats (other
  120.  *    types will be supported eventually).  The number of arguments
  121.  *    determines the dimensionality.
  122.  *
  123.  * Results:
  124.  *    Returns the name of the new matrix.
  125.  *
  126.  * Side effects:
  127.  *    A new matrix (operator) gets created.
  128.  *
  129. \*----------------------------------------------------------------------*/
  130.  
  131. int
  132. Tcl_MatrixCmd(ClientData clientData, Tcl_Interp *interp,
  133.           int argc, char **argv)
  134. {
  135.     register tclMatrix *matPtr;
  136.     int i, length, new, initializer = 0;
  137.     Tcl_HashEntry *hPtr;
  138.     char c, *varName, *value;
  139.  
  140.     if (argc < 3) {
  141.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  142.         " var type dim1 ?dim2? ?dim3? ...\"", (char *) NULL);
  143.     return TCL_ERROR;
  144.     }
  145.  
  146.     if (argc > MAX_ARRAY_DIM + 4) {
  147.     Tcl_AppendResult(interp, "too many dimensions specified",
  148.              (char *) NULL);
  149.     return TCL_ERROR;
  150.     }
  151.  
  152. /* Create hash table on first call */
  153.  
  154.     if ( ! matTable_initted) {
  155.     matTable_initted = 1;
  156.     Tcl_InitHashTable(&matTable, TCL_STRING_KEYS);
  157.     }
  158.  
  159. /* Create matrix data structure */
  160.  
  161.     matPtr = (tclMatrix *) ckalloc(sizeof(tclMatrix));
  162.     matPtr->fdata = NULL;
  163.     matPtr->idata = NULL;
  164.     matPtr->dim = 0;
  165.     matPtr->len = 1;
  166.     for (i = 0; i < MAX_ARRAY_DIM; i++)
  167.     matPtr->n[i] = 1;
  168.  
  169. /* Create name */
  170. /* Local variable mirrors matrix name for GC purposes */
  171.  
  172.     argc--; argv++;
  173.     varName = argv[0];
  174.  
  175.     if (Tcl_GetVar(interp, varName, 0) != NULL) {
  176.     Tcl_AppendResult(interp, "Local variable of name \"", varName,
  177.              "\" already exists", (char *) NULL);
  178.     ckfree((char *) matPtr);
  179.     return TCL_ERROR;
  180.     }
  181.  
  182.     strcpy(matPtr->name, varName);
  183.     if (Tcl_SetVar(interp, varName, matPtr->name, 0) == NULL) {
  184.     Tcl_AppendResult(interp, "unable to set variable to matrix name",
  185.              (char *) NULL);
  186.     ckfree((char *) matPtr);
  187.     return TCL_ERROR;
  188.     }
  189.     Tcl_TraceVar(interp, varName, TCL_TRACE_UNSETS, DeleteMatrixVar,
  190.          (ClientData) matPtr);
  191.  
  192. /* Initialize type */
  193.  
  194.     argc--; argv++;
  195.  
  196.     c = argv[0][0];
  197.     length = strlen(argv[0]);
  198.  
  199.     if ((c == 'f') && (strncmp(argv[0], "float", length) == 0)) {
  200.     matPtr->type = TYPE_FLOAT;
  201.     matPtr->put = MatrixPut_f;
  202.     matPtr->get = MatrixGet_f;
  203.     }
  204.     else if ((c == 'i') && (strncmp(argv[0], "int", length) == 0)) {
  205.     matPtr->type = TYPE_INT;
  206.     matPtr->put = MatrixPut_i;
  207.     matPtr->get = MatrixGet_i;
  208.     }
  209.     else {
  210.     Tcl_AppendResult(interp, "Matrix type \"", argv[0],
  211.         " not supported, should be \"float\"", (char *) NULL);
  212.  
  213.     ckfree((char *) matPtr);
  214.     return TCL_ERROR;
  215.     }
  216.  
  217. /* Initialize dimensions */
  218.  
  219.     for (;;) {
  220.     argc--; argv++;
  221.     if (argc == 0)
  222.         break;
  223.  
  224.     if (strcmp(argv[0], "=") == 0) {
  225.         argc--; argv++;
  226.         initializer = 1;
  227.         break;
  228.     }
  229.     matPtr->n[matPtr->dim] = atoi(argv[0]);
  230.  
  231.     if (matPtr->n[matPtr->dim] < 1) {
  232.         Tcl_AppendResult(interp, "invalid matrix dimension \"", argv[0],
  233.                  "\"", (char *) NULL);
  234.  
  235.         ckfree((char *) matPtr);
  236.         return TCL_ERROR;
  237.     }
  238.     matPtr->len *= matPtr->n[matPtr->dim];
  239.     matPtr->dim++;
  240.     }
  241.  
  242.     if (matPtr->dim < 1) {
  243.     Tcl_AppendResult(interp, "at least one matrix dimension required",
  244.              (char *) NULL);
  245.     ckfree((char *) matPtr);
  246.     return TCL_ERROR;
  247.     }
  248.  
  249. /* Allocate space for data */
  250.  
  251.     switch (matPtr->type) {
  252.     case TYPE_FLOAT:
  253.     matPtr->fdata = (Mat_float *) ckalloc(matPtr->len * sizeof(Mat_float));
  254.     for (i = 0; i < matPtr->len; i++)
  255.         matPtr->fdata[i] = 0.0;
  256.     break;
  257.  
  258.     case TYPE_INT:
  259.     matPtr->idata = (Mat_int *) ckalloc(matPtr->len * sizeof(Mat_int));
  260.     for (i = 0; i < matPtr->len; i++)
  261.         matPtr->idata[i] = 0;
  262.     break;
  263.     }
  264.  
  265. /* Process the initializer, if present */
  266.  
  267.     if (initializer) {
  268.     if (argc == 0) {
  269.         Tcl_AppendResult(interp, "bad initializer syntax",
  270.                  (char *) NULL);
  271.         DeleteMatrixCmd((ClientData) matPtr);
  272.         return TCL_ERROR;
  273.     }
  274.  
  275.     value = strtok(argv[0], " ");
  276.     for (i = 0; ; i++) {
  277.         if ( value == NULL )
  278.         break;
  279.  
  280.         if (i >= matPtr->len)
  281.         break;
  282.  
  283.         (*matPtr->put)((ClientData) matPtr, i, value);
  284.         value = strtok(NULL, " ");
  285.     }
  286.     }
  287.  
  288. /* Create matrix operator */
  289.  
  290.     Tcl_CreateCommand(interp, matPtr->name, MatrixCmd, (ClientData) matPtr,
  291.               DeleteMatrixCmd);
  292.  
  293. /* Create hash table entry for this matrix operator's data */
  294. /* This should never fail */
  295.  
  296.     hPtr = Tcl_CreateHashEntry(&matTable, matPtr->name, &new);
  297.     if ( ! new) {
  298.     Tcl_AppendResult(interp, "Unable to create hash table entry",
  299.              (char *) NULL);
  300.     return TCL_ERROR;
  301.     }
  302.     Tcl_SetHashValue(hPtr, matPtr);
  303.  
  304.     return TCL_OK;
  305. }
  306.  
  307. /*----------------------------------------------------------------------*\
  308.  *
  309.  * Tcl_GetMatrixPtr --
  310.  *
  311.  *    Returns a pointer to the specified matrix operator's data.
  312.  *
  313.  * Results:
  314.  *    None.
  315.  *
  316.  * Side effects:
  317.  *    None.
  318.  *
  319. \*----------------------------------------------------------------------*/
  320.  
  321. tclMatrix *
  322. Tcl_GetMatrixPtr(Tcl_Interp *interp, char *matName)
  323. {
  324.     Tcl_HashEntry *hPtr;
  325.  
  326.     hPtr = Tcl_FindHashEntry(&matTable, matName);
  327.     if (hPtr == NULL) {
  328.     Tcl_AppendResult(interp, "No matrix operator named \"",
  329.              matName, "\"", (char *) NULL);
  330.     return NULL;
  331.     }
  332.     return (tclMatrix *) Tcl_GetHashValue(hPtr);
  333. }
  334.  
  335. /*----------------------------------------------------------------------*\
  336.  *
  337.  *  Tcl_MatrixInstallXtnsn --
  338.  *
  339.  *    Install a tclMatrix extension subcommand.
  340.  *
  341.  * Results:
  342.  *    Should be 1.  Have to think about error results.
  343.  *
  344.  * Side effects:
  345.  *    Enables you to install special purpose compiled code to handle 
  346.  *    custom operations on a tclMatrix.
  347.  *
  348. \*----------------------------------------------------------------------*/
  349.  
  350. static tclMatrixXtnsnDescr *head = (tclMatrixXtnsnDescr *) NULL;
  351. static tclMatrixXtnsnDescr *tail = (tclMatrixXtnsnDescr *) NULL;
  352.  
  353. int Tcl_MatrixInstallXtnsn( char *cmd, tclMatrixXtnsnProc proc )
  354. {
  355. /*
  356.  * My goodness how I hate primitive/pathetic C.  With C++ this
  357.  * could've been as easy as:
  358.  *     List<TclMatrixXtnsnDescr> xtnlist;
  359.  *     xtnlist.append( tclMatrixXtnsnDescr(cmd,proc) );
  360.  * grrrrr.
  361.  */
  362.  
  363.     tclMatrixXtnsnDescr *new =
  364.     (tclMatrixXtnsnDescr *) malloc(sizeof(tclMatrixXtnsnDescr));
  365.  
  366. #ifdef DEBUG
  367.     fprintf(stderr, "Installing a tclMatrix extension -> %s\n", cmd );
  368. #endif
  369.  
  370.     new->cmd = malloc( strlen(cmd)+1 );
  371.     strcpy( new->cmd, cmd );
  372.     new->cmdproc = proc;
  373.     new->next = (tclMatrixXtnsnDescr *) NULL;
  374.  
  375.     if (!head) {
  376.     tail = head = new;
  377.     return 1;
  378.     } else {
  379.     tail = tail->next = new;
  380.     return 1;
  381.     }
  382.     
  383. }
  384.     
  385. /*----------------------------------------------------------------------*\
  386.  *
  387.  * MatrixCmd --
  388.  *
  389.  *    When a Tcl matrix command is invoked, this routine is called.
  390.  *
  391.  * Results:
  392.  *    A standard Tcl result value, usually TCL_OK.
  393.  *    On matrix get commands, one or a number of matrix elements are
  394.  *    printed. 
  395.  *
  396.  * Side effects:
  397.  *    Depends on the matrix command.
  398.  *
  399. \*----------------------------------------------------------------------*/
  400.  
  401. static int
  402. MatrixCmd(ClientData clientData, Tcl_Interp *interp,
  403.       int argc, char **argv)
  404. {
  405.     register tclMatrix *matPtr = (tclMatrix *) clientData;
  406.     int length, put = 0;
  407.     char c, tmp[80];
  408.     char* name = argv[0];
  409.     int nmin[MAX_ARRAY_DIM], nmax[MAX_ARRAY_DIM];
  410.     int i, j, k;
  411.  
  412.     for (i = 0; i < MAX_ARRAY_DIM; i++) {
  413.     nmin[i] = 0;
  414.     nmax[i] = matPtr->n[i]-1;
  415.     }
  416.  
  417. /* First check for a matrix command */
  418.  
  419.     argc--; argv++;
  420.     c = argv[0][0];
  421.     length = strlen(argv[0]);
  422.  
  423. /* delete -- delete the array */
  424.  
  425.     if ((c == 'd') && (strncmp(argv[0], "delete", length) == 0)) {
  426.     fprintf(stderr, "Deleting array %s\n", name);
  427.     Tcl_DeleteCommand(interp, name);
  428.     return TCL_OK;
  429.     }
  430.  
  431. /* dump -- send a nicely formatted listing of the array contents to stdout */
  432. /* (very helpful for debugging) */
  433.  
  434.     else if ((c == 'd') && (strncmp(argv[0], "dump", length) == 0)) {
  435.     for (i = nmin[0]; i <= nmax[0]; i++) {
  436.         for (j = nmin[1]; j <= nmax[1]; j++) {
  437.         for (k = nmin[2]; k <= nmax[2]; k++) {
  438.             (*matPtr->get)((ClientData) matPtr, I3D(i,j,k), tmp);
  439.             printf(tmp);
  440.         }
  441.         if (matPtr->dim > 2)
  442.             printf("\n");
  443.         }
  444.         if (matPtr->dim > 1)
  445.         printf("\n");
  446.     }
  447.     printf("\n");
  448.     return TCL_OK;
  449.     }
  450.  
  451. /* info */
  452.  
  453.     else if ((c == 'i') && (strncmp(argv[0], "info", length) == 0)) {
  454.     for (i = 0; i < matPtr->dim; i++) {
  455.         sprintf(tmp, "%d ", matPtr->n[i]);
  456.         Tcl_AppendResult(interp, tmp, (char *) NULL);
  457.     }
  458.     return TCL_OK;
  459.     }
  460.  
  461. /* redim */
  462.  
  463.     else if ((c == 'r') && (strncmp(argv[0], "redim", length) == 0)) {
  464.     fprintf(stderr, "Redimensioning array %s... NOT!\n", name);
  465.     return TCL_OK;
  466.     }
  467.  
  468. /* Not a "standard" command, check the extension commands. */
  469.  
  470.     {
  471.     tclMatrixXtnsnDescr *p = head;
  472.     for( ; p; p=p->next )
  473.         if ((c == p->cmd[0]) && (strncmp(argv[0],p->cmd,length) == 0)) {
  474. /*        printf( "found a match, invoking %s\n", p->cmd );*/
  475.         return (*(p->cmdproc))( matPtr, interp, --argc, ++argv );
  476.         }
  477.     }
  478.  
  479. /* Must be a put or get.  Get array indices.  */
  480.  
  481.     if (argc < matPtr->dim) {
  482.     Tcl_AppendResult(interp, "not enough dimensions specified for \"",
  483.              name, (char *) NULL);
  484.     return TCL_ERROR;
  485.     }
  486.     for (i = 0; i < matPtr->dim; i++) {
  487.     if (strcmp(argv[0], "*") == 0) {
  488.         nmin[i] = 0;
  489.         nmax[i] = matPtr->n[i]-1;
  490.     }
  491.     else {
  492.         nmin[i] = atoi(argv[0]);
  493.         nmax[i] = nmin[i];
  494.     }
  495.     if (nmin[i] < 0 || nmax[i] > matPtr->n[i]-1) {
  496.         sprintf(tmp, "Array index %d out of bounds: %s; max: %d\n",
  497.             i, argv[0], matPtr->n[i]-1);
  498.         Tcl_AppendResult(interp, tmp, (char *) NULL);
  499.         return TCL_ERROR;
  500.     }
  501.     argc--; argv++;
  502.     }
  503.  
  504. /* If there is an "=" after indicies, it's a put.  Do error checking. */
  505.  
  506.     if (argc > 0) {
  507.     put = 1;
  508.     if (strcmp(argv[0], "=") == 0) {
  509.         argc--; argv++;
  510.         if (argc == 0) {
  511.         Tcl_AppendResult(interp, "no value specified",
  512.                  (char *) NULL);
  513.         return TCL_ERROR;
  514.         }
  515.         else if (argc > 1) {
  516.         Tcl_AppendResult(interp, "extra characters after value: \"",
  517.                  argv[1], "\"", (char *) NULL);
  518.         return TCL_ERROR;
  519.         }
  520.     }
  521.     else {
  522.         Tcl_AppendResult(interp, "extra characters after indices: \"",
  523.                  argv[0], "\"", (char *) NULL);
  524.         return TCL_ERROR;
  525.     }
  526.     }
  527.  
  528. /* Do the get/put. */
  529. /* The loop over all elements takes care of the multi-element cases. */
  530.  
  531.     for (i = nmin[0]; i <= nmax[0]; i++) {
  532.     for (j = nmin[1]; j <= nmax[1]; j++) {
  533.         for (k = nmin[2]; k <= nmax[2]; k++) {
  534.         if (put) 
  535.             (*matPtr->put)((ClientData) matPtr, I3D(i,j,k), argv[0]);
  536.         else {
  537.             (*matPtr->get)((ClientData) matPtr, I3D(i,j,k), tmp);
  538.             Tcl_AppendResult(interp, tmp, (char *) NULL);
  539.         }
  540.         }
  541.     }
  542.     }
  543.  
  544.     return TCL_OK;
  545. }
  546.  
  547. /*----------------------------------------------------------------------*\
  548.  *
  549.  * Routines to handle Matrix get/put dependent on type:
  550.  *
  551.  * MatrixPut_f    MatrixGet_f
  552.  * MatrixPut_i    MatrixGet_i
  553.  *
  554.  * A "put" converts from string format to the intrinsic type, storing into
  555.  * the array.
  556.  *
  557.  * A "get" converts from the intrinsic type to string format, storing into
  558.  * a string buffer.
  559.  *
  560. \*----------------------------------------------------------------------*/
  561.  
  562. static void
  563. MatrixPut_f(ClientData clientData, int index, char *string)
  564. {
  565.     tclMatrix *matPtr = (tclMatrix *) clientData;
  566.  
  567.     matPtr->fdata[index] = atof(string);
  568. }
  569.  
  570. static void
  571. MatrixGet_f(ClientData clientData, int index, char *string)
  572. {
  573.     tclMatrix *matPtr = (tclMatrix *) clientData;
  574.  
  575.     sprintf(string, "%f ", matPtr->fdata[index]);
  576. }
  577.  
  578. static void
  579. MatrixPut_i(ClientData clientData, int index, char *string)
  580. {
  581.     tclMatrix *matPtr = (tclMatrix *) clientData;
  582.  
  583.     matPtr->idata[index] = atoi(string);
  584. }
  585.  
  586. static void
  587. MatrixGet_i(ClientData clientData, int index, char *string)
  588. {
  589.     tclMatrix *matPtr = (tclMatrix *) clientData;
  590.  
  591.     sprintf(string, "%d ", matPtr->idata[index]);
  592. }
  593.  
  594. /*----------------------------------------------------------------------*\
  595.  *
  596.  * DeleteMatrixVar --
  597.  *
  598.  *    Causes matrix command to be deleted.  Invoked when variable
  599.  *    associated with matrix command is unset.
  600.  *
  601.  * Results:
  602.  *    None.
  603.  *
  604.  * Side effects:
  605.  *    See DeleteMatrixCmd.
  606.  *
  607. \*----------------------------------------------------------------------*/
  608.  
  609. static char *
  610. DeleteMatrixVar(ClientData clientData,
  611.         Tcl_Interp *interp, char *name1, char *name2, int flags)
  612. {
  613.     tclMatrix *matPtr = (tclMatrix *) clientData;
  614.  
  615.     if (Tcl_DeleteCommand(interp, matPtr->name) != TCL_OK) 
  616.     fprintf(stderr, "Unable to delete command %s\n", matPtr->name);
  617. #ifdef DEBUG
  618.     else
  619.     fprintf(stderr, "Deleted command %s\n", matPtr->name);
  620. #endif
  621.     return (char *) NULL;
  622. }
  623.  
  624. /*----------------------------------------------------------------------*\
  625.  *
  626.  * DeleteMatrixCmd --
  627.  *
  628.  *    Releases all the resources allocated to the matrix command.
  629.  *    Invoked just before a matrix command is removed from an
  630.  *    interpreter.
  631.  *
  632.  * Results:
  633.  *    None.
  634.  *
  635.  * Side effects:
  636.  *    All memory associated with the matrix operator is freed.
  637.  *
  638. \*----------------------------------------------------------------------*/
  639.  
  640. static void
  641. DeleteMatrixCmd(ClientData clientData)
  642. {
  643.     tclMatrix *matPtr = (tclMatrix *) clientData;
  644.     Tcl_HashEntry *hPtr;
  645.  
  646. #ifdef DEBUG
  647.     fprintf(stderr, "Freeing space associated with matrix %s\n", matPtr->name);
  648. #endif
  649.  
  650.     hPtr = Tcl_FindHashEntry(&matTable, matPtr->name);
  651.     if (hPtr != NULL) 
  652.     Tcl_DeleteHashEntry(hPtr);
  653.  
  654.     if (matPtr->fdata != NULL) 
  655.     ckfree((char *) matPtr->fdata);
  656.  
  657.     if (matPtr->idata != NULL) 
  658.     ckfree((char *) matPtr->idata);
  659.  
  660.     ckfree((char *) matPtr);
  661. }
  662.  
  663.