home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Src / tcl-lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-21  |  20.9 KB  |  793 lines

  1. /*
  2.  *
  3.  * t c l - l i b . c         - A library remplacement for simulating 
  4.  *                  a Tcl interpreter in Scheme
  5.  *
  6.  * Copyright ⌐ 1993-1996 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
  7.  * 
  8.  *
  9.  * Permission to use, copy, and/or distribute this software and its
  10.  * documentation for any purpose and without fee is hereby granted, provided
  11.  * that both the above copyright notice and this permission notice appear in
  12.  * all copies and derived works.  Fees for distribution or use of this
  13.  * software or derived works may only be charged with express written
  14.  * permission of the copyright holder.  
  15.  * This software is provided ``as is'' without express or implied warranty.
  16.  *
  17.  * This software is a derivative work of other copyrighted softwares; the
  18.  * copyright notices of these softwares are placed in the file COPYRIGHTS
  19.  *
  20.  *
  21.  *            Author: Erick Gallesio [eg@unice.fr]
  22.  *    Creation date: 19-Feb-1993 22:15
  23.  * Last file update: 15-Jul-1996 16:44
  24.  *
  25.  */
  26.  
  27.  
  28. #include "stk.h"
  29.  
  30. #ifdef USE_TK
  31. #  include "tk-glue.h"
  32. #else
  33. #  include "tclInt.h"
  34. #endif
  35.  
  36.  
  37. #ifdef USE_TK
  38. #define BUFF_SIZE 100
  39. /******************************************************************************
  40.  *
  41.  *                Eval functions
  42.  *
  43.  ******************************************************************************/
  44.  
  45. int Tcl_GlobalEval(interp, s)
  46.      Tcl_Interp *interp;
  47.      char *s;
  48. {
  49.   char buffer[BUFF_SIZE+3], *ptr = buffer;
  50.   SCM result;
  51.  
  52.   /* 
  53.    * If the callback is nor surrounded by parenthesis, add them. We
  54.    * don't have parenthesis when the callback is a closure. In this
  55.    * case, the callback is simply #p12345. Note that this allow Tk to
  56.    * add some parameters to the callback when needed (on bindings, or
  57.    * scrollbars for instance). To recognize such cases, we look at
  58.    * first character: if it is not an open parenthesis, we add a pair
  59.    * of () around the callback string
  60.    *     
  61.    */
  62.   if (*s == '\0') return TCL_OK;
  63.   if (*s != '(') {
  64.     /* Build the command to evaluate by adding a pair of parenthesis */
  65.     int len = strlen(s);
  66.     
  67.     if (len > BUFF_SIZE) 
  68.       ptr = (char *) must_malloc(len+3);
  69.     sprintf(ptr, "(%s)", s);
  70.     s = ptr;
  71.   }
  72.   result = STk_internal_eval_string(s, ERR_TCL_BACKGROUND, NIL);
  73.   Tcl_ResetResult(interp);
  74.     
  75.   if (ptr != buffer) free(ptr);
  76.  
  77.   if (result != EVAL_ERROR) {
  78.     SCM dumb;
  79.  
  80.     Tcl_SetResult(interp, 
  81.           STk_stringify(STk_convert_for_Tk(result, &dumb), 0), 
  82.           TCL_DYNAMIC);
  83.     /* 
  84.      * Store also the "true" result in STk_last_Tk_result
  85.      * Warning: This pointer inot GC protected. We have to use it very soon 
  86.      * This is a kludge (used in text window)
  87.      */
  88.      STk_last_Tk_result = result;
  89.        
  90.      return (result == Sym_break) ? TCL_BREAK : TCL_OK;
  91.   }
  92.   
  93.   return TCL_ERROR;
  94. }
  95.  
  96. int Tcl_Eval(interp, s)     /* very simplist. */
  97.      Tcl_Interp *interp;    /* But do we need something more clever? */
  98.      char *s;
  99. {
  100.   return Tcl_GlobalEval(interp, s);
  101. }
  102.  
  103.  
  104. /*
  105.  *----------------------------------------------------------------------
  106.  *
  107.  * Tcl_VarEval --
  108.  *
  109.  *    Given a variable number of string arguments, concatenate them
  110.  *    all together and execute the result as a Tcl command.
  111.  *
  112.  * Results:
  113.  *    A standard Tcl return result.  An error message or other
  114.  *    result may be left in interp->result.
  115.  *
  116.  * Side effects:
  117.  *    Depends on what was done by the command.
  118.  *
  119.  *----------------------------------------------------------------------
  120.  */
  121.     /* VARARGS2 */ /* ARGSUSED */
  122. int
  123. Tcl_VarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1)
  124. {
  125.     va_list argList;
  126.     Tcl_DString buf;
  127.     char *string;
  128.     Tcl_Interp *interp;
  129.     int result;
  130.  
  131.     /*
  132.      * Copy the strings one after the other into a single larger
  133.      * string.  Use stack-allocated space for small commands, but if
  134.      * the command gets too large than call ckalloc to create the
  135.      * space.
  136.      */
  137.  
  138.     interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  139.     Tcl_DStringInit(&buf);
  140.     while (1) {
  141.     string = va_arg(argList, char *);
  142.     if (string == NULL) {
  143.         break;
  144.     }
  145.     Tcl_DStringAppend(&buf, string, -1);
  146.     }
  147.     va_end(argList);
  148.  
  149.     result = Tcl_Eval(interp, Tcl_DStringValue(&buf));
  150.     Tcl_DStringFree(&buf);
  151.     return result;
  152. }
  153.  
  154. /******************************************************************************
  155.  *
  156.  *          Variable accesses (GetVar, GetVar2, SetVar, SetVar2)
  157.  *
  158.  ******************************************************************************/
  159.  
  160. char *Tcl_GetVar(interp, var, flags)
  161.      Tcl_Interp *interp;    /* not used */
  162.      char *var;
  163.      int flags;
  164. {
  165.   SCM dumb, V = VCELL(Intern(var));
  166.   return (V == UNBOUND) ? NULL : STk_convert_for_Tk(V, &dumb);
  167. }
  168.  
  169. char *Tcl_GetVar2(interp, name1, name2, flags)
  170.      Tcl_Interp *interp;    /* not used */
  171.      char *name1, *name2;
  172.      int flags;
  173. {
  174.   if (name2 && *name2) {
  175.     char *res, *s = must_malloc(strlen(name1) + strlen(name2) + 3);
  176.  
  177.     sprintf(s, "%s{%s}", name1, name2);
  178.     res = Tcl_GetVar(interp, s, flags);
  179.     free(s);
  180.     return res;
  181.   }
  182.   return Tcl_GetVar(interp, name1, flags);
  183. }
  184.  
  185. char *Tcl_SetVar(interp, var, val, flags)
  186.      Tcl_Interp *interp;
  187.      char *var, *val;
  188.      int flags;
  189. {
  190.   register SCM tmp, value;
  191.  
  192.   tmp = Intern(var);
  193.   if (flags & STk_STRINGIFY) {
  194.     /* Val is already a string, since it comes from Tk */
  195.     value = STk_makestring(val);
  196.   }
  197.   else {
  198.     if (*val) {
  199.       SCM port;
  200.       int eof;
  201.       
  202.       port  = STk_internal_open_input_string(val);
  203.       value = STk_internal_read_from_string(port, &eof, TRUE);
  204.       if (value == EVAL_ERROR) return NULL;
  205.     }
  206.     else 
  207.       value =  STk_makestring("");
  208.   }
  209.  
  210.   VCELL(tmp) = value;
  211.   if (TRACED_VARP(tmp)) STk_change_value(tmp, NIL);
  212.  
  213.   return val;
  214. }
  215.  
  216. char *Tcl_SetVar2(interp, name1, name2, val, flags)
  217.      Tcl_Interp *interp;
  218.      char *name1, *name2, *val;
  219.      int flags;
  220.   if (name2 && *name2) {
  221.     char *res, *s = must_malloc(strlen(name1) + strlen(name2) + 3);
  222.  
  223.     sprintf(s, "%s{%s}", name1, name2);
  224.     res = Tcl_SetVar(interp, s, val, flags);
  225.     free(s);
  226.     return res;
  227.   }
  228.   return Tcl_SetVar(interp, name1, val, flags);
  229. }
  230.  
  231. /******************************************************************************
  232.  *
  233.  *                Tcl command management
  234.  *
  235.  ******************************************************************************/
  236.  
  237.  
  238. int Tcl_DeleteCommand(interp, cmdName)
  239.      Tcl_Interp *interp;
  240.      char *cmdName;
  241. {
  242.   struct Tk_command *W;
  243.   Interp *iPtr = (Interp *) interp;
  244.   Tcl_HashEntry *hPtr;
  245.  
  246.   hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
  247.   if (hPtr == NULL) return -1;
  248.  
  249.   W = (struct Tk_command *) Tcl_GetHashValue(hPtr);
  250.   /* Execute the delete handler */
  251.   if (W->delproc != NULL) (*W->delproc)(W->deldata);
  252.  
  253.   /* Note: W will be freed by the GC */
  254.   Tcl_DeleteHashEntry(hPtr);
  255.  
  256.   /* Delete the command from the callbacks hash table */
  257.   STk_delete_callback(cmdName);
  258.  
  259.   /* Undefine "cmdName" by doing a (set! cmdname #<unbound>) */
  260.   VCELL(Intern(cmdName)) = UNBOUND;
  261.   W->Id[0] = 0; /* To avoid to make again a call to this function from GC */
  262.  
  263.   return 0;
  264. }
  265.  
  266.  
  267. /*
  268.  *----------------------------------------------------------------------
  269.  *
  270.  * Tcl_CreateCommand --
  271.  *
  272.  *    Define a new command in a command table.
  273.  *
  274.  * Results:
  275.  *    The return value is a token for the command, which can
  276.  *    be used in future calls to Tcl_NameOfCommand.
  277.  *
  278.  * Side effects:
  279.  *    If a command named cmdName already exists for interp, it is
  280.  *    deleted.
  281.  *----------------------------------------------------------------------
  282.  */
  283. Tcl_Command
  284. Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
  285.     Tcl_Interp *interp;        /* Token for command interpreter (returned
  286.                  * by a previous call to Tcl_CreateInterp). */
  287.     char *cmdName;        /* Name of command. */
  288.     Tcl_CmdProc *proc;        /* Command procedure to associate with
  289.                  * cmdName. */
  290.     ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  291.     Tcl_CmdDeleteProc *deleteProc;
  292.                 /* If not NULL, gives a procedure to call when
  293.                  * this command is deleted. */
  294. {
  295.   struct Tk_command * W;
  296.  
  297.   /* 
  298.    * There are two parts here.  
  299.    *
  300.    * First part is related to Scheme. We create a new variable and
  301.    * associate the newly created Tk object to it.
  302.    *
  303.    * Second part is quite similar to the Tcl CreateCommand (commands
  304.    * must be stored in a hashtable contained in the interp data
  305.    * structure. This is necessary to delete all the command associated
  306.    * to the interpreter. This is important at least for the "send"
  307.    * command which un-register the interpreter from the X server.
  308.    *
  309.    */
  310.  
  311.   {
  312.     /* First: Scheme part */
  313.     SCM z;
  314.  
  315.     W = (struct Tk_command *) 
  316.               must_malloc(sizeof(struct Tk_command)+strlen(cmdName));
  317.     W->ptr         = clientData;
  318.     W->fct          = proc;
  319.     W->delproc       = deleteProc;
  320.     W->deldata         = clientData;
  321.     strcpy(W->Id, cmdName);
  322.  
  323.     /* Define a Tk-command cell for this new command */
  324.     NEWCELL(z, tc_tkcommand);
  325.     z->storage_as.tk.data   = W;
  326.     z->storage_as.tk.l_data = Ntruth;
  327.     
  328.     /* Define a variable whose name is the command name */
  329.     VCELL(Intern(cmdName)) = z;
  330.   }
  331.   
  332.   {
  333.     /* Second: Tcl part */
  334.     Interp *iPtr = (Interp *) interp;
  335.     register struct Tk_command *cmdPtr;
  336.     Tcl_HashEntry *hPtr;
  337.     int new;
  338.  
  339.     hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
  340.     if (!new) {
  341.       /* Command already exists: delete the old one */
  342.       cmdPtr = (struct Tk_command *) Tcl_GetHashValue(hPtr);
  343.       if (cmdPtr->delproc != NULL) {
  344.     (*cmdPtr->delproc)(cmdPtr->deldata);
  345.       }
  346.       /* Remember that we have already deleted this command for further GC */
  347.       cmdPtr->Id[0] = '\0';
  348.     }
  349.     Tcl_SetHashValue(hPtr, W);
  350.   }
  351.   return (Tcl_Command) W;
  352. }
  353.  
  354.  
  355. /*
  356.  *----------------------------------------------------------------------
  357.  *
  358.  * Tcl_GetCommandName --
  359.  *
  360.  *    Given a token returned by Tcl_CreateCommand, this procedure
  361.  *    returns the current name of the command (which may have changed
  362.  *    due to renaming).
  363.  *
  364.  * Results:
  365.  *    The return value is the name of the given command.
  366.  *
  367.  * Side effects:
  368.  *    None.
  369.  *
  370.  *----------------------------------------------------------------------
  371.  */
  372.  
  373. char *
  374. Tcl_GetCommandName(interp, command)
  375.     Tcl_Interp *interp;        /* Interpreter containing the command. */
  376.     Tcl_Command command;    /* Token for the command, returned by a
  377.                  * previous call to Tcl_CreateCommand.
  378.                  * The command must not have been deleted. */
  379. {
  380.   return ((struct Tk_command *) command)->Id;
  381. }
  382.  
  383. /*
  384.  *----------------------------------------------------------------------
  385.  *
  386.  * Tcl_GetCommandInfo --
  387.  *
  388.  *    Returns various information about a Tcl command.
  389.  *
  390.  * Results:
  391.  *    If cmdName exists in interp, then *infoPtr is modified to
  392.  *    hold information about cmdName and 1 is returned.  If the
  393.  *    command doesn't exist then 0 is returned and *infoPtr isn't
  394.  *    modified.
  395.  *
  396.  * Side effects:
  397.  *    None.
  398.  *
  399.  *----------------------------------------------------------------------
  400.  */
  401.  
  402. int
  403. Tcl_GetCommandInfo(interp, cmdName, infoPtr)
  404.     Tcl_Interp *interp;            /* Interpreter in which to look
  405.                      * for command. */
  406.     char *cmdName;            /* Name of desired command. */
  407.     Tcl_CmdInfo *infoPtr;        /* Where to store information about
  408.                      * command. */
  409. {
  410.     SCM v = Intern(cmdName);
  411.     struct Tk_command *p;
  412.     
  413.     if (NTKCOMMP(VCELL(v))) return 0;
  414.  
  415.     p =  VCELL(v)->storage_as.tk.data;
  416.  
  417.     infoPtr->proc       = p->fct;
  418.     infoPtr->clientData = p->ptr;
  419.     infoPtr->deleteProc = p->delproc;;
  420.     infoPtr->deleteData = NULL;
  421.     return 1;
  422. }
  423.  
  424.  
  425. /******************************************************************************
  426.  *
  427.  *              Tcl interpreter management
  428.  *
  429.  ******************************************************************************/
  430.  
  431. Tcl_Interp *Tcl_CreateInterp()
  432. {
  433.   register Interp *iPtr = (Interp *) ckalloc(sizeof(Interp));
  434.   
  435.   iPtr->result         = iPtr->resultSpace;
  436.   iPtr->freeProc     = 0;
  437.   iPtr->errorLine     = 0;
  438.   iPtr->resultSpace[0]   = 0;
  439.   
  440.   iPtr->appendResult     = NULL;
  441.   iPtr->appendAvl     = 0;
  442.   iPtr->appendUsed     = 0;
  443.  
  444.   strcpy(iPtr->pdFormat, "%g");
  445.  
  446.   iPtr->assocData      = (Tcl_HashTable *) NULL;
  447.  
  448.   /* See Tcl_CreateCommand for this table utility  */
  449.   Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
  450.  
  451.   return (Tcl_Interp *) iPtr;
  452. }
  453.  
  454. /*
  455.  *----------------------------------------------------------------------
  456.  *
  457.  * Tcl_SetAssocData --
  458.  *
  459.  *    Creates a named association between user-specified data, a delete
  460.  *    function and this interpreter. If the association already exists
  461.  *    the data is overwritten with the new data. The delete function will
  462.  *    be invoked when the interpreter is deleted.
  463.  *
  464.  * Results:
  465.  *    None.
  466.  *
  467.  * Side effects:
  468.  *    Sets the associated data, creates the association if needed.
  469.  *
  470.  *----------------------------------------------------------------------
  471.  */
  472.  
  473. void
  474. Tcl_SetAssocData(interp, name, proc, clientData)
  475.     Tcl_Interp *interp;        /* Interpreter to associate with. */
  476.     char *name;            /* Name for association. */
  477.     Tcl_InterpDeleteProc *proc;    /* Proc to call when interpreter is
  478.                                  * about to be deleted. */
  479.     ClientData clientData;    /* One-word value to pass to proc. */
  480. {
  481.     Interp *iPtr = (Interp *) interp;
  482.     AssocData *dPtr;
  483.     Tcl_HashEntry *hPtr;
  484.     int new;
  485.  
  486.     if (iPtr->assocData == (Tcl_HashTable *) NULL) {
  487.     if (iPtr->flags & DELETED) {
  488.         /*
  489.          * Don't create new entries after interpreter deletion
  490.          * has started;  it isn't even safe to muck with the
  491.          * interpreter right now
  492.          */
  493.  
  494.         return;
  495.     }
  496.         iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  497.         Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS);
  498.     }
  499.     hPtr = Tcl_CreateHashEntry(iPtr->assocData, name, &new);
  500.     if (new == 0) {
  501.         dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
  502.     } else {
  503.         dPtr = (AssocData *) ckalloc(sizeof(AssocData));
  504.     }
  505.     dPtr->proc = proc;
  506.     dPtr->clientData = clientData;
  507.  
  508.     Tcl_SetHashValue(hPtr, dPtr);
  509. }
  510.  
  511. /*
  512.  *----------------------------------------------------------------------
  513.  *
  514.  * Tcl_DeleteAssocData --
  515.  *
  516.  *    Deletes a named association of user-specified data with
  517.  *    the specified interpreter.
  518.  *
  519.  * Results:
  520.  *    None.
  521.  *
  522.  * Side effects:
  523.  *    Deletes the association.
  524.  *
  525.  *----------------------------------------------------------------------
  526.  */
  527.  
  528. void
  529. Tcl_DeleteAssocData(interp, name)
  530.     Tcl_Interp *interp;            /* Interpreter to associate with. */
  531.     char *name;                /* Name of association. */
  532. {
  533.     Interp *iPtr = (Interp *) interp;
  534.     AssocData *dPtr;
  535.     Tcl_HashEntry *hPtr;
  536.  
  537.     if (iPtr->assocData == (Tcl_HashTable *) NULL) {
  538.         return;
  539.     }
  540.     hPtr = Tcl_FindHashEntry(iPtr->assocData, name);
  541.     if (hPtr == (Tcl_HashEntry *) NULL) {
  542.         return;
  543.     }
  544.     dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
  545.     ckfree((char *) dPtr);
  546.     Tcl_DeleteHashEntry(hPtr);
  547. }
  548.  
  549. /*
  550.  *----------------------------------------------------------------------
  551.  *
  552.  * Tcl_GetAssocData --
  553.  *
  554.  *    Returns the client data associated with this name in the
  555.  *    specified interpreter.
  556.  *
  557.  * Results:
  558.  *    The client data in the AssocData record denoted by the named
  559.  *    association, or NULL.
  560.  *
  561.  * Side effects:
  562.  *    None.
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566.  
  567. ClientData
  568. Tcl_GetAssocData(interp, name, procPtr)
  569.     Tcl_Interp *interp;            /* Interpreter associated with. */
  570.     char *name;                /* Name of association. */
  571.     Tcl_InterpDeleteProc **procPtr;    /* Pointer to place to store address
  572.                      * of current deletion callback. */
  573. {
  574.     Interp *iPtr = (Interp *) interp;
  575.     AssocData *dPtr;
  576.     Tcl_HashEntry *hPtr;
  577.  
  578.     if (iPtr->assocData == (Tcl_HashTable *) NULL) {
  579.         return (ClientData) NULL;
  580.     }
  581.     hPtr = Tcl_FindHashEntry(iPtr->assocData, name);
  582.     if (hPtr == (Tcl_HashEntry *) NULL) {
  583.         return (ClientData) NULL;
  584.     }
  585.     dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
  586.     if (procPtr != (Tcl_InterpDeleteProc **) NULL) {
  587.         *procPtr = dPtr->proc;
  588.     }
  589.     return dPtr->clientData;
  590. }
  591.  
  592. /*
  593.  *----------------------------------------------------------------------
  594.  *
  595.  * Tcl_InterpDeleted --
  596.  *
  597.  *    Returns nonzero if the interpreter has been deleted with a call
  598.  *    to Tcl_DeleteInterp.
  599.  *
  600.  * Results:
  601.  *    Nonzero if the interpreter is deleted, zero otherwise.
  602.  *
  603.  * Side effects:
  604.  *    None.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608.  
  609. int
  610. Tcl_InterpDeleted(interp)
  611.     Tcl_Interp *interp;
  612. {
  613.     return (((Interp *) interp)->flags & DELETED) ? 1 : 0;
  614. }
  615. /*
  616.  *----------------------------------------------------------------------
  617.  *
  618.  * Tcl_DeleteInterp --
  619.  *
  620.  *    Delete an interpreter and free up all of the resources associated
  621.  *    with it.
  622.  *
  623.  * Results:
  624.  *    None.
  625.  *
  626.  * Side effects:
  627.  *    The interpreter is destroyed.  The caller should never again
  628.  *    use the interp token.
  629.  *
  630.  *----------------------------------------------------------------------
  631.  */
  632. void Tcl_DeleteInterp(interp)
  633.     Tcl_Interp *interp;
  634. {
  635.   Interp *iPtr = (Interp *) interp;
  636.   Tcl_HashEntry *hPtr;
  637.   Tcl_HashSearch search;
  638.   struct Tk_command *W;
  639.  
  640.   if (!iPtr || (iPtr->flags & DELETED)) return;
  641.  
  642.   /* Mark the interpreter as deleted. No further evals will be allowed. */
  643.   iPtr->flags |= DELETED;
  644.   
  645.   /* Delete result space */
  646.   if (iPtr->appendResult != NULL) {
  647.     ckfree(iPtr->appendResult);
  648.   }
  649.   
  650.   /* delete hash table of Tk commands (see Tcl_CreateCommand) */
  651.   for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
  652.        hPtr != NULL; 
  653.        hPtr = Tcl_NextHashEntry(&search)) {
  654.     W = (struct Tk_command *) Tcl_GetHashValue(hPtr);
  655.     Tcl_DeleteCommand(interp, W->Id);
  656.   }
  657.   Tcl_DeleteHashTable(&iPtr->commandTable);
  658.  
  659.   ckfree((char *) iPtr);
  660. }
  661.  
  662.  
  663.  
  664. /*
  665.  *----------------------------------------------------------------------
  666.  *
  667.  * Tcl_GetOpenFile --
  668.  *
  669.  *    Given a name of a channel registered in the given interpreter,
  670.  *    returns a FILE * for it.
  671.  *
  672.  * Results:
  673.  *    A standard Tcl result. If the channel is registered in the given
  674.  *    interpreter and it is managed by the "file" channel driver, and
  675.  *    it is open for the requested mode, then the output parameter
  676.  *    filePtr is set to a FILE * for the underlying file. On error, the
  677.  *    filePtr is not set, TCL_ERROR is returned and an error message is
  678.  *    left in interp->result.
  679.  *
  680.  * Side effects:
  681.  *    May invoke fdopen to create the FILE * for the requested file.
  682.  *
  683.  *----------------------------------------------------------------------
  684.  */
  685.  
  686. int
  687. Tcl_GetOpenFile(interp, string, forWriting, checkUsage, filePtr)
  688.     Tcl_Interp *interp;        /* Interpreter in which to find file. */
  689.     char *string;        /* String that identifies file. */
  690.     int forWriting;        /* 1 means the file is going to be used
  691.                  * for writing, 0 means for reading. */
  692.     int checkUsage;        /* 1 means verify that the file was opened
  693.                  * in a mode that allows the access specified
  694.                  * by "forWriting". Ignored, we always
  695.                                  * check that the channel is open for the
  696.                                  * requested mode. */
  697.     ClientData *filePtr;    /* Store pointer to FILE structure here. */
  698. {
  699.   SCM port;
  700.  
  701.   if ((string[0] == '#') && (string[1] == 'f') && (string[2] == 'i')
  702.       && (string[3] == 'l') && string[4] == 'e') {
  703.     char *end;
  704.     
  705.     port = (SCM) strtoul(string+5, &end, 16);
  706.     if ((end != string+5) && (*end == 0)) {
  707.       /* Verify the given address is a port */
  708.       if (STk_valid_address(port) && (IPORTP(port) || OPORTP(port))) {
  709.     /* Verify the port usage  */
  710.     if (checkUsage && (PORT_FLAGS(port) & PORT_CLOSED)) {
  711.       Tcl_AppendResult(interp, "\"", string,
  712.                "\" is closed", (char *) NULL);
  713.       return TCL_ERROR;
  714.     }
  715.     if (forWriting) {
  716.       if (checkUsage && !OPORTP(port)) {
  717.         Tcl_AppendResult(interp, "\"", string,
  718.             "\" wasn't opened for writing", (char *) NULL);
  719.         return TCL_ERROR;
  720.       }
  721.     }
  722.     else {
  723.        if (!IPORTP(port)) {
  724.          Tcl_AppendResult(interp, "\"", string,
  725.                   "\" wasn't opened for reading", (char *) NULL);
  726.          return TCL_ERROR;
  727.        }
  728.     }
  729.     
  730.     /* File is correct; return it in filePtr */
  731.     *filePtr = PORT_FILE(port);
  732.     return TCL_OK;
  733.       }
  734.     }
  735.   }
  736.   Tcl_AppendResult(interp, "Bad file specification \"", string,
  737.             "\"", (char *) NULL);
  738.   return TCL_ERROR; 
  739. }
  740. #endif
  741.  
  742. /******************************************************************************
  743.  *
  744.  * Tcl channels simulation.
  745.  *
  746.  *    Current version is very minimal. It should probably be extended to be 
  747.  *    more Tcl compatible, since Tcl model is very neat.
  748.  *
  749.  ******************************************************************************/
  750.  
  751. Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, char *fileName, 
  752.                 char *modeString, int permissions)
  753. {
  754.   return (Tcl_Channel) fopen(fileName, modeString);
  755. }
  756.  
  757. int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan)
  758. {
  759.   return fclose((FILE *) chan);
  760. }
  761.  
  762. int Tcl_Read(Tcl_Channel chan, char *bufPtr, int toRead)
  763. {
  764.   return read(fileno((FILE *)chan), bufPtr, toRead);
  765. }
  766.  
  767. int Tcl_Write(Tcl_Channel chan, char *s, int slen)
  768. {
  769.   return write(fileno((FILE *)chan), s, slen);
  770. }
  771.  
  772.  
  773. int Tcl_Seek(Tcl_Channel chan, int offset, int mode)
  774. {
  775.   return fseek((FILE*) chan, (long) offset, mode);
  776. }
  777.  
  778. int Tcl_Flush(Tcl_Channel chan)
  779. {
  780.   return fflush((FILE *) chan);
  781. }
  782.  
  783. Tcl_Channel Tcl_GetStdChannel(int type) /*  TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
  784. {
  785.   switch (type) {
  786.     case TCL_STDIN:  return (Tcl_Channel) STk_stdin;
  787.     case TCL_STDOUT: return (Tcl_Channel) STk_stdout;
  788.     case TCL_STDERR: return (Tcl_Channel) STk_stderr;
  789.   }
  790.   return NULL;
  791. }
  792.