tclMacOSA.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:77k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclMacOSA.c --
  3.  *
  4.  * This contains the initialization routines, and the implementation of
  5.  * the OSA and Component commands.  These commands allow you to connect
  6.  * with the AppleScript or any other OSA component to compile and execute
  7.  * scripts.
  8.  *
  9.  * Copyright (c) 1996 Lucent Technologies and Jim Ingham
  10.  * Copyright (c) 1997 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "License Terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tclMacOSA.c,v 1.10 2002/10/09 11:54:30 das Exp $
  16.  */
  17. #define MAC_TCL
  18. #include <Aliases.h>
  19. #include <string.h>
  20. #include <AppleEvents.h>
  21. #include <AppleScript.h>
  22. #include <OSA.h>
  23. #include <OSAGeneric.h>
  24. #include <Script.h>
  25. #include <FullPath.h>
  26. #include <components.h>
  27. #include <resources.h>
  28. #include <FSpCompat.h>
  29. /* 
  30.  * The following two Includes are from the More Files package.
  31.  */
  32. #include <MoreFiles.h>
  33. #include <FullPath.h>
  34. #include "tcl.h"
  35. #include "tclInt.h"
  36. /*
  37.  * I need this only for the call to FspGetFullPath,
  38.  * I'm really not poking my nose where it does not belong!
  39.  */
  40. #include "tclMacInt.h"
  41. /*
  42.  * Data structures used by the OSA code.
  43.  */
  44. typedef struct tclOSAScript {
  45.     OSAID scriptID;
  46.     OSType languageID;
  47.     long modeFlags;
  48. } tclOSAScript;
  49. typedef struct tclOSAContext {
  50. OSAID contextID;
  51. } tclOSAContext;
  52. typedef struct tclOSAComponent {
  53. char *theName;
  54. ComponentInstance theComponent; /* The OSA Component represented */
  55. long componentFlags;
  56. OSType languageID;
  57. char *languageName;
  58. Tcl_HashTable contextTable;    /* Hash Table linking the context names & ID's */
  59. Tcl_HashTable scriptTable;
  60. Tcl_Interp *theInterp;
  61. OSAActiveUPP defActiveProc;
  62. long defRefCon;
  63. } tclOSAComponent;
  64. /*
  65.  * Prototypes for static procedures. 
  66.  */
  67. static pascal OSErr TclOSAActiveProc _ANSI_ARGS_((long refCon));
  68. static int TclOSACompileCmd _ANSI_ARGS_((Tcl_Interp *interp,
  69.       tclOSAComponent *OSAComponent, int argc,
  70.     CONST char **argv));
  71. static int  tclOSADecompileCmd _ANSI_ARGS_((Tcl_Interp * Interp,
  72.     tclOSAComponent *OSAComponent, int argc,
  73.     CONST char **argv));
  74. static int  tclOSADeleteCmd _ANSI_ARGS_((Tcl_Interp *interp,
  75.     tclOSAComponent *OSAComponent, int argc,
  76.     CONST char **argv));
  77. static int  tclOSAExecuteCmd _ANSI_ARGS_((Tcl_Interp *interp,
  78.     tclOSAComponent *OSAComponent, int argc,
  79.     CONST char **argv));
  80. static int  tclOSAInfoCmd _ANSI_ARGS_((Tcl_Interp *interp,
  81.     tclOSAComponent *OSAComponent, int argc,
  82.     CONST char **argv));
  83. static int  tclOSALoadCmd _ANSI_ARGS_((Tcl_Interp *interp,
  84.     tclOSAComponent *OSAComponent, int argc,
  85.     CONST char **argv));
  86. static int  tclOSARunCmd _ANSI_ARGS_((Tcl_Interp *interp,
  87.     tclOSAComponent *OSAComponent, int argc,
  88.     CONST char **argv));
  89. static int  tclOSAStoreCmd _ANSI_ARGS_((Tcl_Interp *interp,
  90.     tclOSAComponent *OSAComponent, int argc,
  91.     CONST char **argv));
  92. static void GetRawDataFromDescriptor _ANSI_ARGS_((AEDesc *theDesc,
  93.     Ptr destPtr, Size destMaxSize, Size *actSize));
  94. static OSErr  GetCStringFromDescriptor _ANSI_ARGS_((
  95.     AEDesc *sourceDesc, char *resultStr,
  96.     Size resultMaxSize,Size *resultSize));
  97. static int  Tcl_OSAComponentCmd _ANSI_ARGS_((ClientData clientData,
  98.     Tcl_Interp *interp, int argc, CONST char **argv)); 
  99. static void  getSortedHashKeys _ANSI_ARGS_((Tcl_HashTable *theTable,
  100.     CONST char *pattern, Tcl_DString *theResult));
  101. static int  ASCIICompareProc _ANSI_ARGS_((const void *first,
  102.     const void *second));
  103. static int  Tcl_OSACmd _ANSI_ARGS_((ClientData clientData,
  104.     Tcl_Interp *interp, int argc, CONST char **argv)); 
  105. static void  tclOSAClose _ANSI_ARGS_((ClientData clientData));
  106. /*static void  tclOSACloseAll _ANSI_ARGS_((ClientData clientData));*/
  107. static tclOSAComponent *tclOSAMakeNewComponent _ANSI_ARGS_((Tcl_Interp *interp,
  108.     char *cmdName, char *languageName,
  109.     OSType scriptSubtype, long componentFlags));  
  110. static int  prepareScriptData _ANSI_ARGS_((int argc, CONST char **argv,
  111.     Tcl_DString *scrptData ,AEDesc *scrptDesc)); 
  112. static void  tclOSAResultFromID _ANSI_ARGS_((Tcl_Interp *interp,
  113.     ComponentInstance theComponent, OSAID resultID));
  114. static void  tclOSAASError _ANSI_ARGS_((Tcl_Interp * interp,
  115.     ComponentInstance theComponent, char *scriptSource));
  116. static int  tclOSAGetContextID _ANSI_ARGS_((tclOSAComponent *theComponent, 
  117.     CONST char *contextName, OSAID *theContext));
  118. static void  tclOSAAddContext _ANSI_ARGS_((tclOSAComponent *theComponent, 
  119.     char *contextName, const OSAID theContext));
  120. static int  tclOSAMakeContext _ANSI_ARGS_((tclOSAComponent *theComponent, 
  121.     CONST char *contextName, OSAID *theContext));
  122. static int  tclOSADeleteContext _ANSI_ARGS_((tclOSAComponent *theComponent,
  123.     CONST char *contextName)); 
  124. static int  tclOSALoad _ANSI_ARGS_((Tcl_Interp *interp, 
  125.     tclOSAComponent *theComponent, CONST char *resourceName, 
  126.     int resourceNumber, CONST char *fileName,OSAID *resultID));
  127. static int  tclOSAStore _ANSI_ARGS_((Tcl_Interp *interp, 
  128.     tclOSAComponent *theComponent, CONST char *resourceName, 
  129.     int resourceNumber, CONST char *scriptName, CONST char *fileName));
  130. static int  tclOSAAddScript _ANSI_ARGS_((tclOSAComponent *theComponent,
  131.     char *scriptName, long modeFlags, OSAID scriptID)); 
  132. static int  tclOSAGetScriptID _ANSI_ARGS_((tclOSAComponent *theComponent,
  133.     CONST char *scriptName, OSAID *scriptID)); 
  134. static tclOSAScript * tclOSAGetScript _ANSI_ARGS_((tclOSAComponent *theComponent,
  135.     CONST char *scriptName)); 
  136. static int  tclOSADeleteScript _ANSI_ARGS_((tclOSAComponent *theComponent,
  137.     CONST char *scriptName,char *errMsg));
  138. /*
  139.  * "export" is a MetroWerks specific pragma.  It flags the linker that  
  140.  * any symbols that are defined when this pragma is on will be exported 
  141.  * to shared libraries that link with this library.
  142.  */
  143.  
  144. #pragma export on
  145. int Tclapplescript_Init( Tcl_Interp *interp );
  146. #pragma export reset
  147. /*
  148.  *----------------------------------------------------------------------
  149.  *
  150.  * Tclapplescript_Init --
  151.  *
  152.  * Initializes the the OSA command which opens connections to
  153.  * OSA components, creates the AppleScript command, which opens an 
  154.  * instance of the AppleScript component,and constructs the table of
  155.  * available languages.
  156.  *
  157.  * Results:
  158.  * A standard Tcl result.
  159.  *
  160.  * Side Effects:
  161.  * Opens one connection to the AppleScript component, if 
  162.  * available.  Also builds up a table of available OSA languages,
  163.  * and creates the OSA command.
  164.  *
  165.  *----------------------------------------------------------------------
  166.  */
  167. int 
  168. Tclapplescript_Init(
  169.     Tcl_Interp *interp) /* Tcl interpreter. */
  170. {
  171.     char *errMsg = NULL;
  172.     OSErr myErr = noErr;
  173.     Boolean gotAppleScript = false;
  174.     Boolean GotOneOSALanguage = false;
  175.     ComponentDescription compDescr = {
  176. kOSAComponentType,
  177. (OSType) 0,
  178. (OSType) 0,
  179. (long) 0,
  180. (long) 0
  181.     }, *foundComp;
  182.     Component curComponent = (Component) 0;
  183.     ComponentInstance curOpenComponent;
  184.     Tcl_HashTable *ComponentTable;
  185.     Tcl_HashTable *LanguagesTable;
  186.     Tcl_HashEntry *hashEntry;
  187.     int newPtr;
  188.     AEDesc componentName = { typeNull, NULL };
  189.     char nameStr[32];
  190.     Size nameLen;
  191.     long appleScriptFlags;
  192.     /* 
  193.      * Perform the required stubs magic...
  194.      */
  195.      
  196.     if (!Tcl_InitStubs(interp, "8.2", 0)) {
  197. return TCL_ERROR;
  198.     }
  199.     /* 
  200.      * Here We Will Get The Available Osa Languages, Since They Can Only Be 
  201.      * Registered At Startup...  If You Dynamically Load Components, This
  202.      * Will Fail, But This Is Not A Common Thing To Do.
  203.      */
  204.  
  205.     LanguagesTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  206.     if (LanguagesTable == NULL) {
  207. panic("Memory Error Allocating Languages Hash Table");
  208.     }
  209.     Tcl_SetAssocData(interp, "OSAScript_LangTable", NULL, LanguagesTable);
  210.     Tcl_InitHashTable(LanguagesTable, TCL_STRING_KEYS);
  211.     while ((curComponent = FindNextComponent(curComponent, &compDescr)) != 0) {
  212. int nbytes = sizeof(ComponentDescription);
  213. foundComp = (ComponentDescription *)
  214.     ckalloc(sizeof(ComponentDescription));
  215. myErr = GetComponentInfo(curComponent, foundComp, NULL, NULL, NULL);
  216. if (foundComp->componentSubType ==
  217. kOSAGenericScriptingComponentSubtype) {
  218.     /* Skip the generic component */
  219.     ckfree((char *) foundComp);
  220. } else {
  221.     GotOneOSALanguage = true;
  222.     /*
  223.      * This is gross: looks like I have to open the component just  
  224.      * to get its name!!! GetComponentInfo is supposed to return
  225.      * the name, but AppleScript always returns an empty string.
  226.      */
  227.  
  228.     curOpenComponent = OpenComponent(curComponent);
  229.     if (curOpenComponent == NULL) {
  230. Tcl_AppendResult(interp,"Error opening component",
  231. (char *) NULL);
  232. return TCL_ERROR;
  233.     }
  234.  
  235.     myErr = OSAScriptingComponentName(curOpenComponent,&componentName);
  236.     if (myErr == noErr) {
  237. myErr = GetCStringFromDescriptor(&componentName,
  238. nameStr, 31, &nameLen);
  239. AEDisposeDesc(&componentName);
  240.     }
  241.     CloseComponent(curOpenComponent);
  242.     if (myErr == noErr) {
  243. hashEntry = Tcl_CreateHashEntry(LanguagesTable,
  244. nameStr, &newPtr);
  245. Tcl_SetHashValue(hashEntry, (ClientData) foundComp);
  246.     } else {
  247. Tcl_AppendResult(interp,"Error getting componentName.",
  248. (char *) NULL);
  249. return TCL_ERROR;
  250.     }
  251.     /*
  252.      * Make sure AppleScript is loaded, otherwise we will
  253.      * not bother to make the AppleScript command.
  254.      */
  255.     if (foundComp->componentSubType == kAppleScriptSubtype) {
  256. appleScriptFlags = foundComp->componentFlags;
  257. gotAppleScript = true;
  258.     }
  259. }
  260.     }
  261.     /*
  262.      * Create the OSA command.
  263.      */
  264.     if (!GotOneOSALanguage) {
  265. Tcl_AppendResult(interp,"Could not find any OSA languages",
  266. (char *) NULL);
  267. return TCL_ERROR;
  268.     }
  269.     /*
  270.      * Create the Component Assoc Data & put it in the interpreter.
  271.      */
  272.     ComponentTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  273.     if (ComponentTable == NULL) {
  274. panic("Memory Error Allocating Hash Table");
  275.     }
  276.     Tcl_SetAssocData(interp, "OSAScript_CompTable", NULL, ComponentTable);
  277.     Tcl_InitHashTable(ComponentTable, TCL_STRING_KEYS);
  278.     /*
  279.      * The OSA command is not currently supported.  
  280.     Tcl_CreateCommand(interp, "OSA", Tcl_OSACmd, (ClientData) NULL,
  281.     (Tcl_CmdDeleteProc *) NULL);
  282.      */
  283.      
  284.     /* 
  285.      * Open up one AppleScript component, with a default context
  286.      * and tie it to the AppleScript command.
  287.      * If the user just wants single-threaded AppleScript execution
  288.      * this should be enough.
  289.      *
  290.      */
  291.  
  292.     if (gotAppleScript) {
  293. if (tclOSAMakeNewComponent(interp, "AppleScript",
  294. "AppleScript English", kAppleScriptSubtype,
  295. appleScriptFlags) == NULL ) {
  296.     return TCL_ERROR;
  297. }
  298.     }
  299.     return Tcl_PkgProvide(interp, "OSAConnect", "1.0");
  300. }
  301. /*
  302.  *---------------------------------------------------------------------- 
  303.  *
  304.  * Tcl_OSACmd --
  305.  *
  306.  * This is the command that provides the interface to the OSA
  307.  * component manager.  The subcommands are: close: close a component, 
  308.  * info: get info on components open, and open: get a new connection
  309.  * with the Scripting Component
  310.  *
  311.  * Results:
  312.  *   A standard Tcl result.
  313.  *
  314.  * Side effects:
  315.  *   Depends on the subcommand, see the user documentation
  316.  * for more details.
  317.  *
  318.  *----------------------------------------------------------------------
  319.  */
  320.  
  321. int 
  322. Tcl_OSACmd(
  323.     ClientData clientData,
  324.     Tcl_Interp *interp,
  325.     int argc,
  326.     CONST char **argv)
  327. {
  328.     static unsigned short componentCmdIndex = 0;
  329.     char autoName[32];
  330.     char c;
  331.     int length;
  332.     Tcl_HashTable *ComponentTable = NULL;
  333.     if (argc == 1) {
  334. Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  335. argv[0], " option"", (char *) NULL);
  336. return TCL_ERROR;
  337.     }
  338.     c = *argv[1];
  339.     length = strlen(argv[1]);
  340.     /*
  341.      * Query out the Component Table, since most of these commands use it...
  342.      */
  343.     ComponentTable = (Tcl_HashTable *) Tcl_GetAssocData(interp,
  344.     "OSAScript_CompTable", (Tcl_InterpDeleteProc **) NULL);
  345.     if (ComponentTable == NULL) {
  346. Tcl_AppendResult(interp, "Error, could not get the Component Table",
  347. " from the Associated data.", (char *) NULL);
  348. return TCL_ERROR;
  349.     }
  350.     if (c == 'c' && strncmp(argv[1],"close",length) == 0) {
  351. Tcl_HashEntry *hashEntry;
  352. if (argc != 3) {
  353.     Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  354.     argv[0], " ",argv[1], " componentName"",
  355.     (char *) NULL);
  356.     return TCL_ERROR;
  357. }
  358. if ((hashEntry = Tcl_FindHashEntry(ComponentTable,argv[2])) == NULL) {
  359.     Tcl_AppendResult(interp, "Component "", argv[2], "" not found",
  360.     (char *) NULL);
  361.     return TCL_ERROR;
  362. } else {
  363.     Tcl_DeleteCommand(interp,argv[2]);
  364.     return TCL_OK;
  365. }
  366.     } else if (c == 'o' && strncmp(argv[1],"open",length) == 0) {
  367. /*
  368.  * Default language is AppleScript.
  369.  */
  370. OSType scriptSubtype = kAppleScriptSubtype;
  371. char *languageName = "AppleScript English";
  372. char *errMsg = NULL;
  373. ComponentDescription *theCD;
  374. argv += 2;
  375. argc -= 2;
  376.  
  377. while (argc > 0 ) {
  378.     if (*argv[0] == '-') {
  379. c = *(argv[0] + 1);
  380. if (c == 'l' && strcmp(argv[0] + 1, "language") == 0) {
  381.     if (argc == 1) {
  382. Tcl_AppendResult(interp,
  383. "Error - no language provided for the -language switch",
  384. (char *) NULL);
  385. return TCL_ERROR;
  386.     } else {
  387. Tcl_HashEntry *hashEntry;
  388. Tcl_HashSearch search;
  389. Boolean gotIt = false;
  390. Tcl_HashTable *LanguagesTable;
  391. /*
  392.  * Look up the language in the languages table
  393.  * Do a simple strstr match, so AppleScript
  394.  * will match "AppleScript English"...
  395.  */
  396. LanguagesTable = Tcl_GetAssocData(interp,
  397. "OSAScript_LangTable",
  398. (Tcl_InterpDeleteProc **) NULL);
  399. for (hashEntry =
  400.  Tcl_FirstHashEntry(LanguagesTable, &search);
  401.      hashEntry != NULL;
  402.      hashEntry = Tcl_NextHashEntry(&search)) {
  403.     languageName = Tcl_GetHashKey(LanguagesTable,
  404.     hashEntry);
  405.     if (strstr(languageName,argv[1]) != NULL) {
  406. theCD = (ComponentDescription *)
  407.     Tcl_GetHashValue(hashEntry);
  408. gotIt = true;
  409. break;
  410.     }
  411. }
  412. if (!gotIt) {
  413.     Tcl_AppendResult(interp,
  414.     "Error, could not find the language "",
  415.     argv[1],
  416.     "" in the list of known languages.",
  417.     (char *) NULL);
  418.     return TCL_ERROR;
  419. }
  420.     }
  421. }
  422. argc -= 2;
  423. argv += 2;
  424.     } else {
  425. Tcl_AppendResult(interp, "Expected a flag, but got ",
  426. argv[0], (char *) NULL);
  427. return TCL_ERROR;
  428.     }
  429. }
  430. sprintf(autoName, "OSAComponent%-d", componentCmdIndex++);
  431. if (tclOSAMakeNewComponent(interp, autoName, languageName,
  432. theCD->componentSubType, theCD->componentFlags) == NULL ) {
  433.     return TCL_ERROR;
  434. } else {
  435.     Tcl_SetResult(interp,autoName,TCL_VOLATILE);
  436.     return TCL_OK;
  437. }
  438.     } else if (c == 'i' && strncmp(argv[1],"info",length) == 0) {
  439. if (argc == 2) {
  440.     Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  441.     argv[0], " ", argv[1], " what"",
  442.     (char *) NULL);
  443.     return TCL_ERROR;
  444. }
  445.  
  446. c = *argv[2];
  447. length = strlen(argv[2]);
  448. if (c == 'c' && strncmp(argv[2], "components", length) == 0) {
  449.     Tcl_DString theResult;
  450.     Tcl_DStringInit(&theResult);
  451.     if (argc == 3) {
  452. getSortedHashKeys(ComponentTable,(char *) NULL, &theResult);
  453.     } else if (argc == 4) {
  454. getSortedHashKeys(ComponentTable, argv[3], &theResult);
  455.     } else {
  456. Tcl_AppendResult(interp, "Error: wrong # of arguments",
  457. ", should be "", argv[0], " ", argv[1], " ",
  458. argv[2], " ?pattern?".", (char *) NULL);
  459. return TCL_ERROR;
  460.     }
  461.     Tcl_DStringResult(interp, &theResult);
  462.     return TCL_OK;
  463. } else if (c == 'l' && strncmp(argv[2],"languages",length) == 0) {
  464.     Tcl_DString theResult;
  465.     Tcl_HashTable *LanguagesTable;
  466.     Tcl_DStringInit(&theResult);
  467.     LanguagesTable = Tcl_GetAssocData(interp,
  468.     "OSAScript_LangTable", (Tcl_InterpDeleteProc **) NULL);
  469.     if (argc == 3) {
  470. getSortedHashKeys(LanguagesTable, (char *) NULL, &theResult);
  471.     } else if (argc == 4) {
  472. getSortedHashKeys(LanguagesTable, argv[3], &theResult);
  473.     } else {
  474. Tcl_AppendResult(interp, "Error: wrong # of arguments",
  475. ", should be "", argv[0], " ", argv[1], " ",
  476. argv[2], " ?pattern?".", (char *) NULL);
  477. return TCL_ERROR;
  478.     }
  479.     Tcl_DStringResult(interp,&theResult);
  480.     return TCL_OK;
  481. } else {
  482.     Tcl_AppendResult(interp, "Unknown option: ", argv[2],
  483.     " for OSA info, should be one of",
  484.     " "components" or "languages"",
  485.     (char *) NULL);
  486.     return TCL_ERROR;
  487. }
  488.     } else {
  489. Tcl_AppendResult(interp, "Unknown option: ", argv[1],
  490. ", should be one of "open", "close" or "info".",
  491. (char *) NULL);
  492. return TCL_ERROR;
  493.     }
  494.     return TCL_OK;
  495. }
  496. /* 
  497.  *----------------------------------------------------------------------
  498.  *
  499.  * Tcl_OSAComponentCmd --
  500.  *
  501.  * This is the command that provides the interface with an OSA
  502.  * component.  The sub commands are:
  503.  * - compile ? -context context? scriptData
  504.  * compiles the script data, returns the ScriptID
  505.  * - decompile ? -context context? scriptData
  506.  * decompiles the script data, source code
  507.  * - execute ?-context context? scriptData
  508.  * compiles and runs script data
  509.  * - info what: get component info
  510.  * - load ?-flags values? fileName
  511.  * loads & compiles script data from fileName
  512.  * - run scriptId ?options?
  513.  * executes the compiled script 
  514.  *
  515.  * Results:
  516.  * A standard Tcl result
  517.  *
  518.  * Side Effects:
  519.  * Depends on the subcommand, see the user documentation
  520.  * for more details.
  521.  *
  522.  *----------------------------------------------------------------------
  523.  */
  524.  
  525. int 
  526. Tcl_OSAComponentCmd(
  527.     ClientData clientData,
  528.     Tcl_Interp *interp, 
  529.     int argc,
  530.     CONST char **argv)
  531. {
  532.     int length;
  533.     char c;
  534.     tclOSAComponent *OSAComponent = (tclOSAComponent *) clientData;
  535.     if (argc == 1) {
  536. Tcl_AppendResult(interp, "wrong # args: should be "",
  537. argv[0], " option ?arg ...?"",
  538. (char *) NULL);
  539. return TCL_ERROR;
  540.     }
  541.     c = *argv[1];
  542.     length = strlen(argv[1]);
  543.     if (c == 'c' && strncmp(argv[1], "compile", length) == 0) {
  544. return TclOSACompileCmd(interp, OSAComponent, argc, argv);
  545.     } else if (c == 'l' && strncmp(argv[1], "load", length) == 0) {
  546. return tclOSALoadCmd(interp, OSAComponent, argc, argv);
  547.     } else if (c == 'e' && strncmp(argv[1], "execute", length) == 0) {
  548. return tclOSAExecuteCmd(interp, OSAComponent, argc, argv);
  549.     } else if (c == 'i' && strncmp(argv[1], "info", length) == 0) {
  550. return tclOSAInfoCmd(interp, OSAComponent, argc, argv);
  551.     } else if (c == 'd' && strncmp(argv[1], "decompile", length) == 0) {
  552. return tclOSADecompileCmd(interp, OSAComponent, argc, argv);
  553.     } else if (c == 'd' && strncmp(argv[1], "delete", length) == 0) {
  554. return tclOSADeleteCmd(interp, OSAComponent, argc, argv);
  555.     } else if (c == 'r' && strncmp(argv[1], "run", length) == 0) {
  556. return tclOSARunCmd(interp, OSAComponent, argc, argv);
  557.     } else if (c == 's' && strncmp(argv[1], "store", length) == 0) {
  558. return tclOSAStoreCmd(interp, OSAComponent, argc, argv);
  559.     } else {
  560. Tcl_AppendResult(interp,"bad option "", argv[1],
  561. "": should be compile, decompile, delete, ",
  562.  "execute, info, load, run or store",
  563.  (char *) NULL);
  564. return TCL_ERROR;
  565.     }
  566.     return TCL_OK;
  567. }
  568.  
  569. /*
  570.  *----------------------------------------------------------------------
  571.  *
  572.  * TclOSACompileCmd --
  573.  *
  574.  * This is the compile subcommand for the component command.
  575.  *
  576.  * Results:
  577.  * A standard Tcl result
  578.  *
  579.  * Side Effects:
  580.  *   Compiles the script data either into a script or a script
  581.  * context.  Adds the script to the component's script or context
  582.  * table.  Sets interp's result to the name of the new script or
  583.  * context.
  584.  *
  585.  *----------------------------------------------------------------------
  586.  */
  587.  
  588. static int 
  589. TclOSACompileCmd(
  590.     Tcl_Interp *interp,
  591.     tclOSAComponent *OSAComponent,
  592.     int argc,
  593.     CONST char **argv)
  594. {
  595.     int  tclError = TCL_OK;
  596.     int augment = 1;
  597.     int makeContext = 0;
  598.     char c;
  599.     char autoName[16];
  600.     char buffer[32];
  601.     char *resultName;
  602.     Boolean makeNewContext = false;
  603.     Tcl_DString scrptData;
  604.     AEDesc scrptDesc = { typeNull, NULL };
  605.     long modeFlags = kOSAModeCanInteract;
  606.     OSAID resultID = kOSANullScript;
  607.     OSAID contextID = kOSANullScript;
  608.     OSAID parentID = kOSANullScript;
  609.     OSAError osaErr = noErr;
  610.     if (!(OSAComponent->componentFlags && kOSASupportsCompiling)) {
  611. Tcl_AppendResult(interp,
  612. "OSA component does not support compiling",
  613. (char *) NULL);
  614. return TCL_ERROR;
  615.     }
  616.     /* 
  617.      * This signals that we should make up a name, which is the
  618.      * default behavior:
  619.      */
  620.  
  621.     autoName[0] = '';
  622.     resultName = NULL;
  623.     if (argc == 2) {
  624. numArgs:
  625. Tcl_AppendResult(interp,
  626. "wrong # args: should be "", argv[0], " ", argv[1],
  627. " ?options? code"",(char *) NULL);
  628. return TCL_ERROR;
  629.     } 
  630.     argv += 2;
  631.     argc -= 2;
  632.     /*
  633.      * Do the argument parsing.
  634.      */
  635.     while (argc > 0) {
  636. if (*argv[0] == '-') {
  637.     c = *(argv[0] + 1);
  638.     /*
  639.      * "--" is the only switch that has no value, stops processing
  640.      */
  641.     if (c == '-' && *(argv[0] + 2) == '') {
  642. argv += 1;
  643. argc--;
  644. break;
  645.     }
  646.     /*
  647.      * So we can check here a switch with no value.
  648.      */
  649.     if (argc == 1)  {
  650. Tcl_AppendResult(interp,
  651. "no value given for switch: ",
  652. argv[0], (char *) NULL);
  653. return TCL_ERROR;
  654.     }
  655.     if (c == 'c' && strcmp(argv[0] + 1, "context") == 0) {
  656. if (Tcl_GetBoolean(interp, argv[1], &makeContext) != TCL_OK) {
  657.     return TCL_ERROR;
  658. }
  659.     } else if (c == 'a' && strcmp(argv[0] + 1, "augment") == 0) {
  660. /*
  661.  * Augment the current context which implies making a context.
  662.  */
  663. if (Tcl_GetBoolean(interp, argv[1], &augment) != TCL_OK) {
  664.     return TCL_ERROR;
  665. }
  666. makeContext = 1;
  667.     } else if (c == 'n' && strcmp(argv[0] + 1, "name") == 0) {
  668. strncpy(autoName, argv[1], 15);
  669. autoName[15] = '';
  670. resultName = autoName;
  671.     } else if (c == 'p' && strcmp(argv[0] + 1,"parent") == 0) {
  672. /*
  673.  * Since this implies we are compiling into a context, 
  674.  * set makeContext here
  675.  */
  676. if (tclOSAGetContextID(OSAComponent,
  677. argv[1], &parentID) != TCL_OK) {
  678.     Tcl_AppendResult(interp, "context not found "",
  679.     argv[1], """, (char *) NULL);
  680.     return TCL_ERROR;
  681. }
  682. makeContext = 1;
  683.     } else {
  684. Tcl_AppendResult(interp, "bad option "", argv[0],
  685. "": should be -augment, -context, -name or -parent",
  686.  (char *) NULL);
  687. return TCL_ERROR;
  688.     }
  689.     argv += 2;
  690.     argc -= 2;
  691. } else {
  692.     break;
  693. }
  694.     }
  695.     /*
  696.      * Make sure we have some data left...
  697.      */
  698.     if (argc == 0) {
  699. goto numArgs;
  700.     }
  701.     /* 
  702.      * Now if we are making a context, see if it is a new one... 
  703.      * There are three options here:
  704.      * 1) There was no name provided, so we autoName it
  705.      * 2) There was a name, then check and see if it already exists
  706.      *  a) If yes, then makeNewContext is false
  707.      *  b) Otherwise we are making a new context
  708.      */
  709.     if (makeContext) {
  710. modeFlags |= kOSAModeCompileIntoContext;
  711. if (resultName == NULL) {
  712.     /*
  713.      * Auto name the new context.
  714.      */
  715.     resultName = autoName;
  716.     resultID = kOSANullScript;
  717.     makeNewContext = true;
  718. } else if (tclOSAGetContextID(OSAComponent,
  719. resultName, &resultID) == TCL_OK) {
  720. } else { 
  721.     makeNewContext = true;
  722. }
  723. /*
  724.  * Deal with the augment now...
  725.  */
  726. if (augment && !makeNewContext) {
  727.     modeFlags |= kOSAModeAugmentContext;
  728. }
  729.     } else if (resultName == NULL) {
  730. resultName = autoName; /* Auto name the script */
  731.     }
  732.     /*
  733.      * Ok, now we have the options, so we can compile the script data.
  734.      */
  735.     if (prepareScriptData(argc, argv, &scrptData, &scrptDesc) == TCL_ERROR) {
  736. Tcl_DStringResult(interp, &scrptData);
  737. AEDisposeDesc(&scrptDesc);
  738. return TCL_ERROR;
  739.     }
  740.     /* 
  741.      * If we want to use a parent context, we have to make the context 
  742.      * by hand. Note, parentID is only specified when you make a new context. 
  743.      */
  744.     if (parentID != kOSANullScript && makeNewContext) {
  745. AEDesc contextDesc = { typeNull, NULL };
  746. osaErr = OSAMakeContext(OSAComponent->theComponent,
  747. &contextDesc, parentID, &resultID);
  748. modeFlags |= kOSAModeAugmentContext;
  749.     }
  750.     osaErr = OSACompile(OSAComponent->theComponent, &scrptDesc,
  751.     modeFlags, &resultID);
  752.     if (osaErr == noErr) {
  753.  
  754. if (makeContext) {
  755.     /* 
  756.      * For the compiled context to be active, you need to run 
  757.      * the code that is in the context.
  758.      */
  759.     OSAID activateID;
  760.     osaErr = OSAExecute(OSAComponent->theComponent, resultID,
  761.     resultID, kOSAModeCanInteract, &activateID);
  762.     OSADispose(OSAComponent->theComponent, activateID);
  763.     if (osaErr == noErr) {
  764. if (makeNewContext) {
  765.     /*
  766.      * If we have compiled into a context, 
  767.      * this is added to the context table 
  768.      */
  769.  
  770.     tclOSAAddContext(OSAComponent, resultName, resultID);
  771. }
  772. Tcl_SetResult(interp, resultName, TCL_VOLATILE);
  773. tclError = TCL_OK;
  774.     }
  775. } else {
  776.     /*
  777.      * For a script, we return the script name.
  778.      */
  779.     tclOSAAddScript(OSAComponent, resultName, modeFlags, resultID);
  780.     Tcl_SetResult(interp, resultName, TCL_VOLATILE);
  781.     tclError = TCL_OK;
  782. }
  783.     }
  784.     /* 
  785.      * This catches the error either from the original compile, 
  786.      * or from the execute in case makeContext == true
  787.      */
  788.  
  789.     if (osaErr == errOSAScriptError) {
  790. OSADispose(OSAComponent->theComponent, resultID);
  791. tclOSAASError(interp, OSAComponent->theComponent,
  792. Tcl_DStringValue(&scrptData));
  793. tclError = TCL_ERROR;
  794.     } else if (osaErr != noErr)  {
  795. sprintf(buffer, "Error #%-6ld compiling script", osaErr);
  796. Tcl_AppendResult(interp, buffer, (char *) NULL);
  797. tclError = TCL_ERROR;
  798.     } 
  799.     Tcl_DStringFree(&scrptData);
  800.     AEDisposeDesc(&scrptDesc);
  801.     return tclError;
  802. }
  803. /*
  804.  *----------------------------------------------------------------------
  805.  *
  806.  * tclOSADecompileCmd --
  807.  *
  808.  *  This implements the Decompile subcommand of the component command
  809.  *
  810.  * Results:
  811.  * A standard Tcl result.
  812.  *
  813.  * Side Effects:
  814.  *   Decompiles the script, and sets interp's result to the
  815.  * decompiled script data.
  816.  *
  817.  *----------------------------------------------------------------------
  818.  */
  819.  
  820. static int 
  821. tclOSADecompileCmd(
  822.     Tcl_Interp * interp,
  823.     tclOSAComponent *OSAComponent,
  824.     int argc, 
  825.     CONST char **argv)
  826. {
  827.     AEDesc resultingSourceData = { typeChar, NULL };
  828.     OSAID scriptID;
  829.     Boolean isContext;
  830.     long result;
  831.     OSErr sysErr = noErr;
  832.  
  833.     if (argc == 2) {
  834. Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  835. argv[0], " ",argv[1], " scriptName "", (char *) NULL );
  836. return TCL_ERROR;
  837.     }
  838.  
  839.     if (!(OSAComponent->componentFlags && kOSASupportsGetSource)) {
  840. Tcl_AppendResult(interp,
  841. "Error, this component does not support get source",
  842. (char *) NULL);
  843. return TCL_ERROR;
  844.     }
  845.  
  846.     if (tclOSAGetScriptID(OSAComponent, argv[2], &scriptID) == TCL_OK) {
  847. isContext = false;
  848.     } else if (tclOSAGetContextID(OSAComponent, argv[2], &scriptID)
  849.     == TCL_OK ) {
  850. isContext = true;
  851.     } else { 
  852. Tcl_AppendResult(interp, "Could not find script "",
  853. argv[2], """, (char *) NULL);
  854. return TCL_ERROR;
  855.     }
  856.     OSAGetScriptInfo(OSAComponent->theComponent, scriptID,
  857.     kOSACanGetSource, &result);
  858.     sysErr = OSAGetSource(OSAComponent->theComponent, 
  859.     scriptID, typeChar, &resultingSourceData);
  860.     if (sysErr == noErr) {
  861. Tcl_DString theResult;
  862. Tcl_DStringInit(&theResult);
  863. Tcl_DStringAppend(&theResult, *resultingSourceData.dataHandle,
  864. GetHandleSize(resultingSourceData.dataHandle));
  865. Tcl_DStringResult(interp, &theResult);
  866. AEDisposeDesc(&resultingSourceData);
  867. return TCL_OK;
  868.     } else {
  869. Tcl_AppendResult(interp, "Error getting source data", (char *) NULL);
  870. AEDisposeDesc(&resultingSourceData);
  871. return TCL_ERROR;
  872.     }
  873. }
  874.  
  875. /*
  876.  *----------------------------------------------------------------------
  877.  *
  878.  * tclOSADeleteCmd --
  879.  *
  880.  * This implements the Delete subcommand of the Component command.
  881.  *
  882.  * Results:
  883.  * A standard Tcl result.
  884.  *
  885.  * Side Effects:
  886.  *   Deletes a script from the script list of the given component.
  887.  * Removes all references to the script, and frees the memory
  888.  * associated with it.
  889.  *
  890.  *----------------------------------------------------------------------
  891.  */
  892.  
  893. static int 
  894. tclOSADeleteCmd(
  895.     Tcl_Interp *interp,
  896.     tclOSAComponent *OSAComponent,
  897.     int argc,
  898.     CONST char **argv)
  899. {
  900.     char c,*errMsg = NULL;
  901.     int length;
  902.  
  903.     if (argc < 4) {
  904. Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  905. argv[0], " ", argv[1], " what scriptName", (char *) NULL);
  906. return TCL_ERROR;
  907.     }
  908.  
  909.     c = *argv[2];
  910.     length = strlen(argv[2]);
  911.     if (c == 'c' && strncmp(argv[2], "context", length) == 0) {
  912. if (strcmp(argv[3], "global") == 0) {
  913.     Tcl_AppendResult(interp, "You cannot delete the global context",
  914.     (char *) NULL);
  915.     return TCL_ERROR;
  916. } else if (tclOSADeleteContext(OSAComponent, argv[3]) != TCL_OK) {
  917.     Tcl_AppendResult(interp, "Error deleting script "", argv[2],
  918.     "": ", errMsg, (char *) NULL);
  919.     ckfree(errMsg);
  920.     return TCL_ERROR;
  921. }
  922.     } else if (c == 's' && strncmp(argv[2], "script", length) == 0) {
  923. if (tclOSADeleteScript(OSAComponent, argv[3], errMsg) != TCL_OK) {
  924.     Tcl_AppendResult(interp, "Error deleting script "", argv[3],
  925.     "": ", errMsg, (char *) NULL);
  926.     ckfree(errMsg);
  927.     return TCL_ERROR;
  928. }
  929.     } else {
  930. Tcl_AppendResult(interp,"Unknown value ", argv[2],
  931. " should be one of ",
  932. ""context" or "script".",
  933. (char *) NULL );
  934. return TCL_ERROR;
  935.     }
  936.     return TCL_OK;
  937. }
  938. /*
  939.  *---------------------------------------------------------------------- 
  940.  *
  941.  * tclOSAExecuteCmd --
  942.  *
  943.  * This implements the execute subcommand of the component command.
  944.  *
  945.  * Results:
  946.  * A standard Tcl result.
  947.  *
  948.  * Side effects:
  949.  * Executes the given script data, and sets interp's result to
  950.  * the OSA component's return value.
  951.  *
  952.  *---------------------------------------------------------------------- 
  953.  */
  954.  
  955. static int 
  956. tclOSAExecuteCmd(
  957.     Tcl_Interp *interp,
  958.     tclOSAComponent *OSAComponent,
  959.     int argc,
  960.     CONST char **argv)
  961. {
  962.     int tclError = TCL_OK, resID = 128;
  963.     char c,buffer[32],
  964. *contextName = NULL,*scriptName = NULL, *resName = NULL;
  965.     Boolean makeNewContext = false,makeContext = false;
  966.     AEDesc scrptDesc = { typeNull, NULL };
  967.     long modeFlags = kOSAModeCanInteract;
  968.     OSAID resultID = kOSANullScript,
  969. contextID = kOSANullScript,
  970. parentID = kOSANullScript;
  971.     Tcl_DString scrptData;
  972.     OSAError osaErr = noErr;
  973.     OSErr  sysErr = noErr;
  974.     if (argc == 2) {
  975. Tcl_AppendResult(interp,
  976. "Error, no script data for "", argv[0],
  977. " run"", (char *) NULL);
  978. return TCL_ERROR;
  979.     } 
  980.     argv += 2;
  981.     argc -= 2;
  982.     /*
  983.      * Set the context to the global context by default.
  984.      * Then parse the argument list for switches
  985.      */
  986.     tclOSAGetContextID(OSAComponent, "global", &contextID);
  987.     while (argc > 0) {
  988. if (*argv[0] == '-') {
  989.     c = *(argv[0] + 1);
  990.     /*
  991.      * "--" is the only switch that has no value.
  992.      */
  993.     if (c == '-' && *(argv[0] + 2) == '') {
  994. argv += 1;
  995. argc--;
  996. break;
  997.     }
  998.     /*
  999.      * So we can check here for a switch with no value.
  1000.      */
  1001.     if (argc == 1)  {
  1002. Tcl_AppendResult(interp,
  1003. "Error, no value given for switch ",
  1004. argv[0], (char *) NULL);
  1005. return TCL_ERROR;
  1006.     }
  1007.     if (c == 'c' && strcmp(argv[0] + 1, "context") == 0) {
  1008. if (tclOSAGetContextID(OSAComponent,
  1009. argv[1], &contextID) == TCL_OK) {
  1010. } else {
  1011.     Tcl_AppendResult(interp, "Script context "",
  1012.     argv[1], "" not found", (char *) NULL);
  1013.     return TCL_ERROR;
  1014. }
  1015.     } else { 
  1016. Tcl_AppendResult(interp, "Error, invalid switch ", argv[0],
  1017. " should be "-context"", (char *) NULL);
  1018. return TCL_ERROR;
  1019.     }
  1020.     argv += 2;
  1021.     argc -= 2;
  1022. } else {
  1023.     break;
  1024. }
  1025.     }
  1026.     if (argc == 0) {
  1027. Tcl_AppendResult(interp, "Error, no script data", (char *) NULL);
  1028. return TCL_ERROR;
  1029.     }
  1030.     if (prepareScriptData(argc, argv, &scrptData, &scrptDesc) == TCL_ERROR) {
  1031. Tcl_DStringResult(interp, &scrptData);
  1032. AEDisposeDesc(&scrptDesc);
  1033. return TCL_ERROR;
  1034.     }
  1035.     /*
  1036.      * Now try to compile and run, but check to make sure the
  1037.      * component supports the one shot deal
  1038.      */
  1039.     if (OSAComponent->componentFlags && kOSASupportsConvenience) {
  1040. osaErr = OSACompileExecute(OSAComponent->theComponent,
  1041. &scrptDesc, contextID, modeFlags, &resultID);
  1042.     } else {
  1043. /*
  1044.  * If not, we have to do this ourselves
  1045.  */
  1046. if (OSAComponent->componentFlags && kOSASupportsCompiling) {
  1047.     OSAID compiledID = kOSANullScript;
  1048.     osaErr = OSACompile(OSAComponent->theComponent, &scrptDesc,
  1049.     modeFlags, &compiledID);
  1050.     if (osaErr == noErr) {
  1051. osaErr = OSAExecute(OSAComponent->theComponent, compiledID,
  1052. contextID, modeFlags, &resultID);
  1053.     }
  1054.     OSADispose(OSAComponent->theComponent, compiledID);
  1055. } else {
  1056.     /*
  1057.      * The scripting component had better be able to load text data...
  1058.      */
  1059.     OSAID loadedID = kOSANullScript;
  1060.     scrptDesc.descriptorType = OSAComponent->languageID;
  1061.     osaErr = OSALoad(OSAComponent->theComponent, &scrptDesc,
  1062.     modeFlags, &loadedID);
  1063.     if (osaErr == noErr) {
  1064. OSAExecute(OSAComponent->theComponent, loadedID,
  1065. contextID, modeFlags, &resultID);
  1066.     }
  1067.     OSADispose(OSAComponent->theComponent, loadedID);
  1068. }
  1069.     }
  1070.     if (osaErr == errOSAScriptError) {
  1071. tclOSAASError(interp, OSAComponent->theComponent,
  1072. Tcl_DStringValue(&scrptData));
  1073. tclError = TCL_ERROR;
  1074.     } else if (osaErr != noErr) {
  1075. sprintf(buffer, "Error #%-6ld compiling script", osaErr);
  1076. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1077. tclError = TCL_ERROR;
  1078.     } else  {
  1079. tclOSAResultFromID(interp, OSAComponent->theComponent, resultID);
  1080. osaErr = OSADispose(OSAComponent->theComponent, resultID);
  1081. tclError = TCL_OK;
  1082.     } 
  1083.     Tcl_DStringFree(&scrptData);
  1084.     AEDisposeDesc(&scrptDesc);
  1085.     return tclError;
  1086. /*
  1087.  *----------------------------------------------------------------------
  1088.  *
  1089.  * tclOSAInfoCmd --
  1090.  *
  1091.  * This implements the Info subcommand of the component command
  1092.  *
  1093.  * Results:
  1094.  * A standard Tcl result.
  1095.  *
  1096.  * Side effects:
  1097.  * Info on scripts and contexts.  See the user documentation for details.
  1098.  *
  1099.  *----------------------------------------------------------------------
  1100.  */
  1101. static int 
  1102. tclOSAInfoCmd(
  1103.     Tcl_Interp *interp,
  1104.     tclOSAComponent *OSAComponent,
  1105.     int argc, 
  1106.     CONST char **argv)
  1107. {
  1108.     char c;
  1109.     int length;
  1110.     Tcl_DString theResult;
  1111.     if (argc == 2) {
  1112. Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  1113. argv[0], " ", argv[1], " what "", (char *) NULL );
  1114. return TCL_ERROR;
  1115.     }
  1116.  
  1117.     c = *argv[2];
  1118.     length = strlen(argv[2]);
  1119.     if (c == 's' && strncmp(argv[2], "scripts", length) == 0) {
  1120. Tcl_DStringInit(&theResult);
  1121. if (argc == 3) {
  1122.     getSortedHashKeys(&OSAComponent->scriptTable, (char *) NULL,
  1123.     &theResult);
  1124. } else if (argc == 4) {
  1125.     getSortedHashKeys(&OSAComponent->scriptTable, argv[3], &theResult);
  1126. } else {
  1127.     Tcl_AppendResult(interp, "Error: wrong # of arguments,",
  1128.     " should be "", argv[0], " ", argv[1], " ",
  1129.     argv[2], " ?pattern?", (char *) NULL);
  1130.     return TCL_ERROR;
  1131. }
  1132. Tcl_DStringResult(interp, &theResult);
  1133. return TCL_OK;
  1134.     } else if (c == 'c' && strncmp(argv[2], "contexts", length) == 0) {
  1135. Tcl_DStringInit(&theResult);
  1136. if (argc == 3) {
  1137.     getSortedHashKeys(&OSAComponent->contextTable, (char *) NULL,
  1138.    &theResult);
  1139. } else if (argc == 4) {
  1140.     getSortedHashKeys(&OSAComponent->contextTable,
  1141.     argv[3], &theResult);
  1142. } else {
  1143.     Tcl_AppendResult(interp, "Error: wrong # of arguments for ,",
  1144.     " should be "", argv[0], " ", argv[1], " ",
  1145.     argv[2], " ?pattern?", (char *) NULL);
  1146.     return TCL_ERROR;
  1147. }
  1148. Tcl_DStringResult(interp, &theResult);
  1149. return TCL_OK;
  1150.     } else if (c == 'l' && strncmp(argv[2], "language", length) == 0) {
  1151. Tcl_SetResult(interp, OSAComponent->languageName, TCL_STATIC);
  1152. return TCL_OK;
  1153.     } else {
  1154. Tcl_AppendResult(interp, "Unknown argument "", argv[2],
  1155. "" for "", argv[0], " info ", should be one of ",
  1156. ""scripts" "language", or "contexts"",
  1157. (char *) NULL);
  1158. return TCL_ERROR;
  1159.     } 
  1160. }
  1161. /*
  1162.  *----------------------------------------------------------------------
  1163.  *
  1164.  * tclOSALoadCmd --
  1165.  *
  1166.  * This is the load subcommand for the Component Command
  1167.  *
  1168.  *
  1169.  * Results:
  1170.  * A standard Tcl result.
  1171.  *
  1172.  * Side effects:
  1173.  * Loads script data from the given file, creates a new context
  1174.  * for it, and sets interp's result to the name of the new context.
  1175.  *
  1176.  *----------------------------------------------------------------------
  1177.  */
  1178.  
  1179. static int 
  1180. tclOSALoadCmd(
  1181.     Tcl_Interp *interp,
  1182.     tclOSAComponent *OSAComponent,
  1183.     int argc,
  1184.     CONST char **argv)
  1185. {
  1186.     int tclError = TCL_OK, resID = 128;
  1187.     char c, autoName[24],
  1188. *contextName = NULL, *scriptName = NULL;
  1189.     CONST char *resName = NULL;
  1190.     Boolean makeNewContext = false, makeContext = false;
  1191.     AEDesc scrptDesc = { typeNull, NULL };
  1192.     long modeFlags = kOSAModeCanInteract;
  1193.     OSAID resultID = kOSANullScript,
  1194. contextID = kOSANullScript,
  1195. parentID = kOSANullScript;
  1196.     OSAError osaErr = noErr;
  1197.     OSErr  sysErr = noErr;
  1198.     long scptInfo;
  1199.     autoName[0] = '';
  1200.     scriptName = autoName;
  1201.     contextName = autoName;
  1202.     if (argc == 2) {
  1203. Tcl_AppendResult(interp,
  1204. "Error, no data for "", argv[0], " ", argv[1],
  1205. """, (char *) NULL);
  1206. return TCL_ERROR;
  1207.     } 
  1208.     argv += 2;
  1209.     argc -= 2;
  1210.     /*
  1211.      * Do the argument parsing.
  1212.      */
  1213.     while (argc > 0) {
  1214. if (*argv[0] == '-') {
  1215.     c = *(argv[0] + 1);
  1216.     /*
  1217.      * "--" is the only switch that has no value.
  1218.      */
  1219.     if (c == '-' && *(argv[0] + 2) == '') {
  1220. argv += 1;
  1221. argc--;
  1222. break;
  1223.     }
  1224.     /*
  1225.      * So we can check here a switch with no value.
  1226.      */
  1227.     if (argc == 1)  {
  1228. Tcl_AppendResult(interp, "Error, no value given for switch ",
  1229. argv[0], (char *) NULL);
  1230. return TCL_ERROR;
  1231.     }
  1232.     if (c == 'r' && strcmp(argv[0] + 1, "rsrcname") == 0) {
  1233. resName = argv[1];
  1234.     } else if (c == 'r' && strcmp(argv[0] + 1, "rsrcid") == 0) {
  1235. if (Tcl_GetInt(interp, argv[1], &resID) != TCL_OK) {
  1236.     Tcl_AppendResult(interp,
  1237.     "Error getting resource ID", (char *) NULL);
  1238.     return TCL_ERROR;
  1239. }
  1240.     } else {
  1241. Tcl_AppendResult(interp, "Error, invalid switch ", argv[0],
  1242. " should be "--", "-rsrcname" or "-rsrcid"",
  1243. (char *) NULL);
  1244. return TCL_ERROR;
  1245.     }
  1246.     argv += 2;
  1247.     argc -= 2;
  1248. } else {
  1249.     break;
  1250. }
  1251.     }
  1252.     /*
  1253.      * Ok, now we have the options, so we can load the resource,
  1254.      */
  1255.     if (argc == 0) {
  1256. Tcl_AppendResult(interp, "Error, no filename given", (char *) NULL);
  1257. return TCL_ERROR;
  1258.     }
  1259.     if (tclOSALoad(interp, OSAComponent, resName, resID,
  1260.     argv[0], &resultID) != TCL_OK) {
  1261. Tcl_AppendResult(interp, "Error in load command", (char *) NULL);
  1262. return TCL_ERROR;
  1263.     }
  1264.  
  1265.     /*
  1266.      *  Now find out whether we have a script, or a script context.
  1267.      */
  1268.  
  1269.     OSAGetScriptInfo(OSAComponent->theComponent, resultID,
  1270.     kOSAScriptIsTypeScriptContext, &scptInfo);
  1271.     
  1272.     if (scptInfo) {
  1273. autoName[0] = '';
  1274. tclOSAAddContext(OSAComponent, autoName, resultID);
  1275. Tcl_SetResult(interp, autoName, TCL_VOLATILE);
  1276.     } else {
  1277. /*
  1278.  * For a script, we return the script name
  1279.  */
  1280. autoName[0] = '';
  1281. tclOSAAddScript(OSAComponent, autoName, kOSAModeCanInteract, resultID);
  1282. Tcl_SetResult(interp, autoName, TCL_VOLATILE);
  1283.     }  
  1284.     return TCL_OK;
  1285. }
  1286. /*
  1287.  *----------------------------------------------------------------------
  1288.  *
  1289.  * tclOSARunCmd --
  1290.  *
  1291.  * This implements the run subcommand of the component command
  1292.  *
  1293.  * Results:
  1294.  * A standard Tcl result.
  1295.  *
  1296.  * Side effects:
  1297.  * Runs the given compiled script, and returns the OSA
  1298.  * component's result.
  1299.  *
  1300.  *----------------------------------------------------------------------
  1301.  */
  1302.  
  1303. static int 
  1304. tclOSARunCmd(
  1305.     Tcl_Interp *interp,
  1306.     tclOSAComponent *OSAComponent,
  1307.     int argc,
  1308.     CONST char **argv)
  1309. {
  1310.     int tclError = TCL_OK,
  1311. resID = 128;
  1312.     char c, *contextName = NULL,
  1313. *scriptName = NULL, 
  1314. *resName = NULL;
  1315.     AEDesc scrptDesc = { typeNull, NULL };
  1316.     long modeFlags = kOSAModeCanInteract;
  1317.     OSAID resultID = kOSANullScript,
  1318. contextID = kOSANullScript,
  1319. parentID = kOSANullScript;
  1320.     OSAError osaErr = noErr;
  1321.     OSErr sysErr = noErr;
  1322.     CONST char *componentName = argv[0];
  1323.     OSAID scriptID;
  1324.     if (argc == 2) {
  1325. Tcl_AppendResult(interp, "Wrong # of arguments, should be "",
  1326. argv[0], " ", argv[1], " scriptName", (char *) NULL);
  1327. return TCL_ERROR;
  1328.     }
  1329.     /*
  1330.      * Set the context to the global context for this component,
  1331.      * as a default
  1332.      */
  1333.     if (tclOSAGetContextID(OSAComponent, "global", &contextID) != TCL_OK) {
  1334. Tcl_AppendResult(interp,
  1335. "Could not find the global context for component ",
  1336. OSAComponent->theName, (char *) NULL );
  1337. return TCL_ERROR;
  1338.     }
  1339.     /*
  1340.      * Now parse the argument list for switches
  1341.      */
  1342.     argv += 2;
  1343.     argc -= 2;
  1344.     while (argc > 0) {
  1345. if (*argv[0] == '-') {
  1346.     c = *(argv[0] + 1);
  1347.     /*
  1348.      * "--" is the only switch that has no value
  1349.      */
  1350.     if (c == '-' && *(argv[0] + 2) == '') {
  1351. argv += 1;
  1352. argc--;
  1353. break;
  1354.     }
  1355.     /*
  1356.      * So we can check here for a switch with no value.
  1357.      */
  1358.     if (argc == 1)  {
  1359. Tcl_AppendResult(interp, "Error, no value given for switch ",
  1360. argv[0], (char *) NULL);
  1361. return TCL_ERROR;
  1362.     }
  1363.     if (c == 'c' && strcmp(argv[0] + 1, "context") == 0) {
  1364. if (argc == 1) {
  1365.     Tcl_AppendResult(interp,
  1366.     "Error - no context provided for the -context switch",
  1367.     (char *) NULL);
  1368.     return TCL_ERROR;
  1369. } else if (tclOSAGetContextID(OSAComponent,
  1370. argv[1], &contextID) == TCL_OK) {
  1371. } else {
  1372.     Tcl_AppendResult(interp, "Script context "", argv[1],
  1373.     "" not found", (char *) NULL);
  1374.     return TCL_ERROR;
  1375.     } else {
  1376. Tcl_AppendResult(interp, "Error, invalid switch ", argv[0],
  1377. " for ", componentName,
  1378. " should be "-context"", (char *) NULL);
  1379. return TCL_ERROR;
  1380.     }
  1381.     argv += 2;
  1382.     argc -= 2;
  1383. } else {
  1384.     break;
  1385. }
  1386.     }
  1387.     if (tclOSAGetScriptID(OSAComponent, argv[0], &scriptID) != TCL_OK) {
  1388. if (tclOSAGetContextID(OSAComponent, argv[0], &scriptID) != TCL_OK) {
  1389.     Tcl_AppendResult(interp, "Could not find script "",
  1390.     argv[2], """, (char *) NULL);
  1391.     return TCL_ERROR;
  1392. }
  1393.     }
  1394.     sysErr = OSAExecute(OSAComponent->theComponent,
  1395.     scriptID, contextID, modeFlags, &resultID);
  1396.     if (sysErr == errOSAScriptError) {
  1397. tclOSAASError(interp, OSAComponent->theComponent, (char *) NULL);
  1398. tclError = TCL_ERROR;
  1399.     } else if (sysErr != noErr) {
  1400. char buffer[32];
  1401. sprintf(buffer, "Error #%6.6d encountered in run", sysErr);
  1402. Tcl_SetResult(interp, buffer, TCL_VOLATILE);
  1403. tclError = TCL_ERROR;
  1404.     } else {
  1405. tclOSAResultFromID(interp, OSAComponent->theComponent, resultID );
  1406.     }
  1407.     OSADispose(OSAComponent->theComponent, resultID);
  1408.     return tclError;
  1409. }
  1410. /*
  1411.  *----------------------------------------------------------------------
  1412.  *
  1413.  * tclOSAStoreCmd --
  1414.  *
  1415.  * This implements the store subcommand of the component command
  1416.  *
  1417.  * Results:
  1418.  * A standard Tcl result.
  1419.  *
  1420.  * Side effects:
  1421.  * Runs the given compiled script, and returns the OSA
  1422.  * component's result.
  1423.  *
  1424.  *----------------------------------------------------------------------
  1425.  */
  1426.  
  1427. static int 
  1428. tclOSAStoreCmd(
  1429.     Tcl_Interp *interp,
  1430.     tclOSAComponent *OSAComponent,
  1431.     int argc,
  1432.     CONST char **argv)
  1433. {
  1434.     int tclError = TCL_OK, resID = 128;
  1435.     char c, *contextName = NULL, *scriptName = NULL;
  1436.     CONST char *resName = NULL;
  1437.     Boolean makeNewContext = false, makeContext = false;
  1438.     AEDesc scrptDesc = { typeNull, NULL };
  1439.     long modeFlags = kOSAModeCanInteract;
  1440.     OSAID resultID = kOSANullScript,
  1441. contextID = kOSANullScript,
  1442. parentID = kOSANullScript;
  1443.     OSAError osaErr = noErr;
  1444.     OSErr  sysErr = noErr;
  1445.     if (argc == 2) {
  1446. Tcl_AppendResult(interp, "Error, no data for "", argv[0],
  1447. " ",argv[1], """, (char *) NULL);
  1448. return TCL_ERROR;
  1449.     } 
  1450.     argv += 2;
  1451.     argc -= 2;
  1452.     /*
  1453.      * Do the argument parsing
  1454.      */
  1455.     while (argc > 0) {
  1456. if (*argv[0] == '-') {
  1457.     c = *(argv[0] + 1);
  1458.     /*
  1459.      * "--" is the only switch that has no value
  1460.      */
  1461.     if (c == '-' && *(argv[0] + 2) == '') {
  1462. argv += 1;
  1463. argc--;
  1464. break;
  1465.     }
  1466.     /*
  1467.      * So we can check here a switch with no value.
  1468.      */
  1469.     if (argc == 1)  {
  1470. Tcl_AppendResult(interp,
  1471. "Error, no value given for switch ",
  1472. argv[0], (char *) NULL);
  1473. return TCL_ERROR;
  1474.     }
  1475.     if (c == 'r' && strcmp(argv[0] + 1, "rsrcname") == 0) {
  1476. resName = argv[1];
  1477.     } else if (c == 'r' && strcmp(argv[0] + 1, "rsrcid") == 0) {
  1478. if (Tcl_GetInt(interp, argv[1], &resID) != TCL_OK) {
  1479.     Tcl_AppendResult(interp,
  1480.     "Error getting resource ID", (char *) NULL);
  1481.     return TCL_ERROR;
  1482. }
  1483.     } else {
  1484. Tcl_AppendResult(interp, "Error, invalid switch ", argv[0],
  1485. " should be "--", "-rsrcname" or "-rsrcid"",
  1486. (char *) NULL);
  1487. return TCL_ERROR;
  1488.     }
  1489.     argv += 2;
  1490.     argc -= 2;
  1491. } else {
  1492.     break;
  1493. }
  1494.     }
  1495.     /*
  1496.      * Ok, now we have the options, so we can load the resource,
  1497.      */
  1498.     if (argc != 2) {
  1499. Tcl_AppendResult(interp, "Error, wrong # of arguments, should be ",
  1500. argv[0], " ", argv[1], "?option flag? scriptName fileName",
  1501. (char *) NULL);
  1502. return TCL_ERROR;
  1503.     }
  1504.     if (tclOSAStore(interp, OSAComponent, resName, resID,
  1505.     argv[0], argv[1]) != TCL_OK) {
  1506. Tcl_AppendResult(interp, "Error in load command", (char *) NULL);
  1507. return TCL_ERROR;
  1508.     } else {
  1509. Tcl_ResetResult(interp);
  1510. tclError = TCL_OK;
  1511.     }
  1512.     
  1513.     return tclError;
  1514. }
  1515. /*
  1516.  *----------------------------------------------------------------------
  1517.  *
  1518.  * tclOSAMakeNewComponent --
  1519.  *
  1520.  * Makes a command cmdName to represent a new connection to the
  1521.  * OSA component with componentSubType scriptSubtype.
  1522.  *
  1523.  * Results: 
  1524.  * Returns the tclOSAComponent structure for the connection.
  1525.  *
  1526.  * Side Effects: 
  1527.  * Adds a new element to the component table.  If there is an
  1528.  * error, then the result of the Tcl interpreter interp is set
  1529.  * to an appropriate error message.
  1530.  *
  1531.  *----------------------------------------------------------------------
  1532.  */
  1533.  
  1534. tclOSAComponent *
  1535. tclOSAMakeNewComponent(
  1536.     Tcl_Interp *interp,
  1537.     char *cmdName,
  1538.     char *languageName, 
  1539.     OSType scriptSubtype,
  1540.     long componentFlags) 
  1541. {
  1542.     char buffer[32];
  1543.     AEDesc resultingName = {typeNull, NULL};
  1544.     AEDesc nullDesc = {typeNull, NULL };
  1545.     OSAID globalContext;
  1546.     char global[] = "global";
  1547.     int nbytes;
  1548.     ComponentDescription requestedComponent = {
  1549. kOSAComponentType,
  1550. (OSType) 0,
  1551. (OSType) 0,
  1552. (long int) 0,
  1553. (long int) 0
  1554.     };
  1555.     Tcl_HashTable *ComponentTable;
  1556.     Component foundComponent = NULL;
  1557.     OSAActiveUPP myActiveProcUPP;
  1558.     tclOSAComponent *newComponent;
  1559.     Tcl_HashEntry *hashEntry;
  1560.     int newPtr;
  1561.     requestedComponent.componentSubType = scriptSubtype;
  1562.     nbytes = sizeof(tclOSAComponent);
  1563.     newComponent = (tclOSAComponent *) ckalloc(sizeof(tclOSAComponent));
  1564.     if (newComponent == NULL) {
  1565. goto CleanUp;
  1566.     }
  1567.     foundComponent = FindNextComponent(0, &requestedComponent);
  1568.     if (foundComponent == 0) {
  1569. Tcl_AppendResult(interp,
  1570. "Could not find component of requested type", (char *) NULL);
  1571. goto CleanUp;
  1572.     } 
  1573.     newComponent->theComponent = OpenComponent(foundComponent); 
  1574.     if (newComponent->theComponent == NULL) {
  1575. Tcl_AppendResult(interp,
  1576. "Could not open component of the requested type",
  1577. (char *) NULL);
  1578. goto CleanUp;
  1579.     }
  1580.     newComponent->languageName = (char *) ckalloc(strlen(languageName) + 1);
  1581.     strcpy(newComponent->languageName,languageName);
  1582.     newComponent->componentFlags = componentFlags;
  1583.     newComponent->theInterp = interp;
  1584.     Tcl_InitHashTable(&newComponent->contextTable, TCL_STRING_KEYS);
  1585.     Tcl_InitHashTable(&newComponent->scriptTable, TCL_STRING_KEYS);
  1586.     if (tclOSAMakeContext(newComponent, global, &globalContext) != TCL_OK) {
  1587. sprintf(buffer, "%-6.6ld", globalContext);
  1588. Tcl_AppendResult(interp, "Error ", buffer, " making ", global,
  1589. " context.", (char *) NULL);
  1590. goto CleanUp;
  1591.     }
  1592.     
  1593.     newComponent->languageID = scriptSubtype;
  1594.     newComponent->theName = (char *) ckalloc(strlen(cmdName) + 1 );
  1595.     strcpy(newComponent->theName, cmdName);
  1596.     Tcl_CreateCommand(interp, newComponent->theName, Tcl_OSAComponentCmd,
  1597.     (ClientData) newComponent, tclOSAClose);
  1598.     /*
  1599.      * Register the new component with the component table
  1600.      */ 
  1601.     ComponentTable = (Tcl_HashTable *) Tcl_GetAssocData(interp,
  1602.     "OSAScript_CompTable", (Tcl_InterpDeleteProc **) NULL);
  1603.     if (ComponentTable == NULL) {
  1604. Tcl_AppendResult(interp, "Error, could not get the Component Table",
  1605. " from the Associated data.", (char *) NULL);
  1606. return (tclOSAComponent *) NULL;
  1607.     }
  1608.     hashEntry = Tcl_CreateHashEntry(ComponentTable,
  1609.     newComponent->theName, &newPtr);
  1610.     Tcl_SetHashValue(hashEntry, (ClientData) newComponent);
  1611.     /*
  1612.      * Set the active proc to call Tcl_DoOneEvent() while idle
  1613.      */
  1614.     if (OSAGetActiveProc(newComponent->theComponent,
  1615.     &newComponent->defActiveProc, &newComponent->defRefCon) != noErr ) {
  1616.      /* TODO -- clean up here... */
  1617.     }
  1618.     myActiveProcUPP = NewOSAActiveUPP(TclOSAActiveProc);
  1619.     OSASetActiveProc(newComponent->theComponent,
  1620.     myActiveProcUPP, (long) newComponent);
  1621.     return newComponent;
  1622.     CleanUp:
  1623.     ckfree((char *) newComponent);
  1624.     return (tclOSAComponent *) NULL;
  1625. }
  1626. /*
  1627.  *----------------------------------------------------------------------
  1628.  *
  1629.  * tclOSAClose --
  1630.  *
  1631.  * This procedure closes the connection to an OSA component, and 
  1632.  * deletes all the script and context data associated with it.
  1633.  * It is the command deletion callback for the component's command.
  1634.  *
  1635.  * Results:
  1636.  * None
  1637.  *
  1638.  * Side effects:
  1639.  * Closes the connection, and releases all the script data.
  1640.  *
  1641.  *----------------------------------------------------------------------
  1642.  */
  1643. void 
  1644. tclOSAClose(
  1645.     ClientData clientData) 
  1646. {
  1647.     tclOSAComponent *theComponent = (tclOSAComponent *) clientData;
  1648.     Tcl_HashEntry *hashEntry;
  1649.     Tcl_HashSearch search;
  1650.     tclOSAScript *theScript;
  1651.     Tcl_HashTable *ComponentTable;
  1652.     /* 
  1653.      * Delete the context and script tables 
  1654.      * the memory for the language name, and
  1655.      * the hash entry.
  1656.      */
  1657.     for (hashEntry = Tcl_FirstHashEntry(&theComponent->scriptTable, &search);
  1658.  hashEntry != NULL;
  1659.  hashEntry = Tcl_NextHashEntry(&search)) {
  1660. theScript = (tclOSAScript *) Tcl_GetHashValue(hashEntry);
  1661. OSADispose(theComponent->theComponent, theScript->scriptID);
  1662. ckfree((char *) theScript);
  1663. Tcl_DeleteHashEntry(hashEntry);
  1664.     }
  1665.     for (hashEntry = Tcl_FirstHashEntry(&theComponent->contextTable, &search);
  1666.  hashEntry != NULL;
  1667.  hashEntry = Tcl_NextHashEntry(&search)) {
  1668. Tcl_DeleteHashEntry(hashEntry);
  1669.     }
  1670.     ckfree(theComponent->languageName);
  1671.     ckfree(theComponent->theName);
  1672.     /*
  1673.      * Finally close the component
  1674.      */
  1675.     CloseComponent(theComponent->theComponent);
  1676.     ComponentTable = (Tcl_HashTable *)
  1677. Tcl_GetAssocData(theComponent->theInterp,
  1678. "OSAScript_CompTable", (Tcl_InterpDeleteProc **) NULL);
  1679.     if (ComponentTable == NULL) {
  1680. panic("Error, could not get the Component Table from the Associated data.");
  1681.     }
  1682.     hashEntry = Tcl_FindHashEntry(ComponentTable, theComponent->theName);
  1683.     if (hashEntry != NULL) {
  1684. Tcl_DeleteHashEntry(hashEntry);
  1685.     }
  1686.     
  1687.     ckfree((char *) theComponent);
  1688. }
  1689. /*
  1690.  *----------------------------------------------------------------------
  1691.  *
  1692.  * tclOSAGetContextID  --
  1693.  *
  1694.  * This returns the context ID, given the component name.
  1695.  *
  1696.  * Results:
  1697.  * A context ID
  1698.  *
  1699.  * Side effects:
  1700.  * None
  1701.  *
  1702.  *----------------------------------------------------------------------
  1703.  */
  1704. static int 
  1705. tclOSAGetContextID(
  1706.     tclOSAComponent *theComponent, 
  1707.     CONST char *contextName, 
  1708.     OSAID *theContext)
  1709. {
  1710.     Tcl_HashEntry *hashEntry;
  1711.     tclOSAContext *contextStruct;
  1712.     if ((hashEntry = Tcl_FindHashEntry(&theComponent->contextTable,
  1713.     contextName)) == NULL ) {
  1714. return TCL_ERROR;
  1715.     } else {
  1716. contextStruct = (tclOSAContext *) Tcl_GetHashValue(hashEntry);
  1717. *theContext = contextStruct->contextID;
  1718.     }
  1719.     return TCL_OK;
  1720. }
  1721. /*
  1722.  *----------------------------------------------------------------------
  1723.  *
  1724.  * tclOSAAddContext  --
  1725.  *
  1726.  * This adds the context ID, with the name contextName.  If the
  1727.  * name is passed in as a NULL string, space is malloc'ed for the
  1728.  * string and a new name is made up, if the string is empty, you
  1729.  * must have allocated enough space ( 24 characters is fine) for
  1730.  * the name, which is made up and passed out.
  1731.  *
  1732.  * Results:
  1733.  * Nothing
  1734.  *
  1735.  * Side effects:
  1736.  * Adds the script context to the component's context table.
  1737.  *
  1738.  *----------------------------------------------------------------------
  1739.  */
  1740. static void 
  1741. tclOSAAddContext(
  1742.     tclOSAComponent *theComponent, 
  1743.     char *contextName,
  1744.     const OSAID theContext)
  1745. {
  1746.     static unsigned short contextIndex = 0;
  1747.     tclOSAContext *contextStruct;
  1748.     Tcl_HashEntry *hashEntry;
  1749.     int newPtr;
  1750.     if (contextName == NULL) {
  1751. contextName = ckalloc(16 + TCL_INTEGER_SPACE);
  1752. sprintf(contextName, "OSAContext%d", contextIndex++);
  1753.     } else if (*contextName == '') {
  1754. sprintf(contextName, "OSAContext%d", contextIndex++);
  1755.     }
  1756.     hashEntry = Tcl_CreateHashEntry(&theComponent->contextTable,
  1757.     contextName, &newPtr);
  1758.     contextStruct = (tclOSAContext *) ckalloc(sizeof(tclOSAContext));
  1759.     contextStruct->contextID = theContext;
  1760.     Tcl_SetHashValue(hashEntry,(ClientData) contextStruct);
  1761. }
  1762. /*
  1763.  *----------------------------------------------------------------------
  1764.  *
  1765.  * tclOSADeleteContext  --
  1766.  *
  1767.  * This deletes the context struct, with the name contextName.  
  1768.  *
  1769.  * Results:
  1770.  * A normal Tcl result
  1771.  *
  1772.  * Side effects:
  1773.  * Removes the script context to the component's context table,
  1774.  * and deletes the data associated with it.
  1775.  *
  1776.  *----------------------------------------------------------------------
  1777.  */
  1778. static int 
  1779. tclOSADeleteContext(
  1780.     tclOSAComponent *theComponent,
  1781.     CONST char *contextName) 
  1782. {
  1783.     Tcl_HashEntry *hashEntry;
  1784.     tclOSAContext *contextStruct;
  1785.     hashEntry = Tcl_FindHashEntry(&theComponent->contextTable, contextName);
  1786.     if (hashEntry == NULL) {
  1787. return TCL_ERROR;
  1788.     }
  1789.     /*
  1790.      * Dispose of the script context data
  1791.      */
  1792.     contextStruct = (tclOSAContext *) Tcl_GetHashValue(hashEntry);
  1793.     OSADispose(theComponent->theComponent,contextStruct->contextID);
  1794.     /*
  1795.      * Then the hash entry
  1796.      */
  1797.     ckfree((char *) contextStruct);
  1798.     Tcl_DeleteHashEntry(hashEntry);
  1799.     return TCL_OK;
  1800. }
  1801. /*
  1802.  *----------------------------------------------------------------------
  1803.  *
  1804.  * tclOSAMakeContext  --
  1805.  *
  1806.  * This makes the context with name contextName, and returns the ID.
  1807.  *
  1808.  * Results:
  1809.  * A standard Tcl result
  1810.  *
  1811.  * Side effects:
  1812.  * Makes a new context, adds it to the context table, and returns 
  1813.  * the new contextID in the variable theContext.
  1814.  *
  1815.  *----------------------------------------------------------------------
  1816.  */
  1817. static int 
  1818. tclOSAMakeContext(
  1819.     tclOSAComponent *theComponent, 
  1820.     CONST char *contextName,
  1821.     OSAID *theContext)
  1822. {
  1823.     AEDesc contextNameDesc = {typeNull, NULL};
  1824.     OSAError osaErr = noErr;
  1825.     AECreateDesc(typeChar, contextName, strlen(contextName), &contextNameDesc);
  1826.     osaErr = OSAMakeContext(theComponent->theComponent, &contextNameDesc,
  1827.     kOSANullScript, theContext);
  1828.     AEDisposeDesc(&contextNameDesc);
  1829.     if (osaErr == noErr) {
  1830. char name[24];
  1831. strncpy(name, contextName, 23);
  1832. name[23] = '';
  1833. tclOSAAddContext(theComponent, name, *theContext);
  1834.     } else {
  1835. *theContext = (OSAID) osaErr;
  1836. return TCL_ERROR;
  1837.     }
  1838.     return TCL_OK;
  1839. }
  1840. /*
  1841.  *----------------------------------------------------------------------
  1842.  *
  1843.  * tclOSAStore --
  1844.  *
  1845.  * This stores a script resource from the file named in fileName.
  1846.  *
  1847.  * Most of this routine is caged from the Tcl Source, from the
  1848.  * Tcl_MacSourceCmd routine.  This is good, since it ensures this
  1849.  * follows the same convention for looking up files as Tcl.
  1850.  *
  1851.  * Returns
  1852.  * A standard Tcl result.
  1853.  *
  1854.  * Side Effects:
  1855.  * The given script data is stored in the file fileName.
  1856.  *
  1857.  *----------------------------------------------------------------------
  1858.  */
  1859.  
  1860. int
  1861. tclOSAStore(
  1862.     Tcl_Interp *interp,
  1863.     tclOSAComponent *theComponent,
  1864.     CONST char *resourceName,
  1865.     int resourceNumber, 
  1866.     CONST char *scriptName,
  1867.     CONST char *fileName)
  1868. {
  1869.     Handle resHandle;
  1870.     Str255 rezName;
  1871.     int result = TCL_OK;
  1872.     short saveRef, fileRef = -1;
  1873.     char idStr[16 + TCL_INTEGER_SPACE];
  1874.     FSSpec fileSpec;
  1875.     Tcl_DString ds, buffer;
  1876.     CONST char *nativeName;
  1877.     OSErr myErr = noErr;
  1878.     OSAID scriptID;
  1879.     Size scriptSize;
  1880.     AEDesc scriptData;
  1881.     /*
  1882.      * First extract the script data
  1883.      */
  1884.     if (tclOSAGetScriptID(theComponent, scriptName, &scriptID) != TCL_OK ) {
  1885. if (tclOSAGetContextID(theComponent, scriptName, &scriptID)
  1886. != TCL_OK) {
  1887.     Tcl_AppendResult(interp, "Error getting script ",
  1888.     scriptName, (char *) NULL);
  1889.     return TCL_ERROR;
  1890. }
  1891.     }
  1892.     myErr = OSAStore(theComponent->theComponent, scriptID,
  1893.     typeOSAGenericStorage, kOSAModeNull, &scriptData);
  1894.     if (myErr != noErr) {
  1895. sprintf(idStr, "%d", myErr);
  1896. Tcl_AppendResult(interp, "Error #", idStr,
  1897. " storing script ", scriptName, (char *) NULL);
  1898. return TCL_ERROR;
  1899.     }
  1900.     /*
  1901.      * Now try to open the output file
  1902.      */
  1903.     saveRef = CurResFile();
  1904.     if (fileName != NULL) {
  1905. OSErr err;
  1906. if (Tcl_TranslateFileName(interp, fileName, &buffer) == NULL) {
  1907.     return TCL_ERROR;
  1908. }
  1909. nativeName = Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&buffer), 
  1910.          Tcl_DStringLength(&buffer), &ds);
  1911. err = FSpLocationFromPath(strlen(nativeName), nativeName, &fileSpec);
  1912. Tcl_DStringFree(&ds);
  1913. Tcl_DStringFree(&buffer);
  1914. if ((err != noErr) && (err != fnfErr)) {
  1915.     Tcl_AppendResult(interp,
  1916.     "Error getting a location for the file: "", 
  1917.     fileName, "".", NULL);
  1918.     return TCL_ERROR;
  1919. }
  1920. FSpCreateResFileCompatTcl(&fileSpec,
  1921. 'WiSH', 'osas', smSystemScript);
  1922. myErr = ResError();
  1923. if ((myErr != noErr) && (myErr != dupFNErr)) {
  1924.     sprintf(idStr, "%d", myErr);
  1925.     Tcl_AppendResult(interp, "Error #", idStr,
  1926.     " creating new resource file ", fileName, (char *) NULL);
  1927.     result = TCL_ERROR;
  1928.     goto rezEvalCleanUp;
  1929. }
  1930. fileRef = FSpOpenResFileCompatTcl(&fileSpec, fsRdWrPerm);
  1931. if (fileRef == -1) {
  1932.     Tcl_AppendResult(interp, "Error reading the file: "", 
  1933.     fileName, "".", NULL);
  1934.     result = TCL_ERROR;
  1935.     goto rezEvalCleanUp;
  1936. }
  1937. UseResFile(fileRef);
  1938.     } else {
  1939. /*
  1940.  * The default behavior will search through all open resource files.
  1941.  * This may not be the behavior you desire.  If you want the behavior
  1942.  * of this call to *only* search the application resource fork, you
  1943.  * must call UseResFile at this point to set it to the application
  1944.  * file.  This means you must have already obtained the application's 
  1945.  * fileRef when the application started up.
  1946.  */
  1947.     }
  1948.     /*
  1949.      * Load the resource by name 
  1950.      */
  1951.     if (resourceName != NULL) {
  1952. strcpy((char *) rezName + 1, resourceName);
  1953. rezName[0] = strlen(resourceName);
  1954. resHandle = Get1NamedResource('scpt', rezName);
  1955. myErr = ResError();
  1956. if (resHandle == NULL) {
  1957.     /*
  1958.      * These signify either the resource or the resource
  1959.      * type were not found
  1960.      */
  1961.     if (myErr == resNotFound || myErr == noErr) {
  1962. short uniqueID;
  1963. while ((uniqueID = Unique1ID('scpt') ) < 128) {}
  1964. AddResource(scriptData.dataHandle, 'scpt', uniqueID, rezName);
  1965. WriteResource(resHandle);
  1966. result = TCL_OK;
  1967. goto rezEvalCleanUp;
  1968.     } else {
  1969. /*
  1970.  * This means there was some other error, for now
  1971.  * I just bag out.
  1972.  */
  1973. sprintf(idStr, "%d", myErr);
  1974. Tcl_AppendResult(interp, "Error #", idStr,
  1975. " opening scpt resource named ", resourceName,
  1976. " in file ", fileName, (char *) NULL);
  1977. result = TCL_ERROR;
  1978. goto rezEvalCleanUp;
  1979.     }
  1980. }
  1981. /*
  1982.  * Or ID
  1983.  */ 
  1984.     } else {
  1985. resHandle = Get1Resource('scpt', resourceNumber);
  1986. rezName[0] = 0;
  1987. rezName[1] = '';
  1988. myErr = ResError();
  1989. if (resHandle == NULL) {
  1990.     /*
  1991.      * These signify either the resource or the resource
  1992.      * type were not found
  1993.      */
  1994.     if (myErr == resNotFound || myErr == noErr) {
  1995. AddResource(scriptData.dataHandle, 'scpt',
  1996. resourceNumber, rezName);
  1997. WriteResource(resHandle);
  1998. result = TCL_OK;
  1999. goto rezEvalCleanUp;
  2000.     } else {
  2001. /*
  2002.  * This means there was some other error, for now
  2003.  * I just bag out */
  2004. sprintf(idStr, "%d", myErr);
  2005. Tcl_AppendResult(interp, "Error #", idStr,
  2006. " opening scpt resource named ", resourceName,
  2007. " in file ", fileName,(char *) NULL);
  2008. result = TCL_ERROR;
  2009. goto rezEvalCleanUp;
  2010.     }
  2011.     }
  2012.     /* 
  2013.      * We get to here if the resource exists 
  2014.      * we just copy into it... 
  2015.      */
  2016.  
  2017.     scriptSize = GetHandleSize(scriptData.dataHandle);
  2018.     SetHandleSize(resHandle, scriptSize);
  2019.     HLock(scriptData.dataHandle);
  2020.     HLock(resHandle);
  2021.     BlockMove(*scriptData.dataHandle, *resHandle,scriptSize);
  2022.     HUnlock(scriptData.dataHandle);
  2023.     HUnlock(resHandle);
  2024.     ChangedResource(resHandle);
  2025.     WriteResource(resHandle);
  2026.     result = TCL_OK;
  2027.     goto rezEvalCleanUp;
  2028.     rezEvalError:
  2029.     sprintf(idStr, "ID=%d", resourceNumber);
  2030.     Tcl_AppendResult(interp, "The resource "",
  2031.     (resourceName != NULL ? resourceName : idStr),
  2032.     "" could not be loaded from ",
  2033.     (fileName != NULL ? fileName : "application"),
  2034.     ".", NULL);
  2035.     rezEvalCleanUp:
  2036.     if (fileRef != -1) {
  2037. CloseResFile(fileRef);
  2038.     }
  2039.     UseResFile(saveRef);
  2040.     return result;
  2041. }
  2042. /*----------------------------------------------------------------------
  2043.  *
  2044.  * tclOSALoad --
  2045.  *
  2046.  * This loads a script resource from the file named in fileName.
  2047.  * Most of this routine is caged from the Tcl Source, from the
  2048.  * Tcl_MacSourceCmd routine.  This is good, since it ensures this
  2049.  * follows the same convention for looking up files as Tcl.
  2050.  *
  2051.  * Returns
  2052.  * A standard Tcl result.
  2053.  *
  2054.  * Side Effects:
  2055.  * A new script element is created from the data in the file.
  2056.  * The script ID is passed out in the variable resultID.
  2057.  *
  2058.  *----------------------------------------------------------------------
  2059.  */
  2060.  
  2061. int
  2062. tclOSALoad(
  2063.     Tcl_Interp *interp,
  2064.     tclOSAComponent *theComponent,
  2065.     CONST char *resourceName,
  2066.     int resourceNumber, 
  2067.     CONST char *fileName,
  2068.     OSAID *resultID)
  2069. {
  2070.     Handle sourceData;
  2071.     Str255 rezName;
  2072.     int result = TCL_OK;
  2073.     short saveRef, fileRef = -1;
  2074.     char idStr[16 + TCL_INTEGER_SPACE];
  2075.     FSSpec fileSpec;
  2076.     Tcl_DString ds, buffer;
  2077.     CONST char *nativeName;
  2078.     saveRef = CurResFile();
  2079.     if (fileName != NULL) {
  2080. OSErr err;
  2081. if (Tcl_TranslateFileName(interp, fileName, &buffer) == NULL) {
  2082.     return TCL_ERROR;
  2083. }
  2084. nativeName = Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&buffer), 
  2085.          Tcl_DStringLength(&buffer), &ds);
  2086. err = FSpLocationFromPath(strlen(nativeName), nativeName, &fileSpec);
  2087. Tcl_DStringFree(&ds);
  2088. Tcl_DStringFree(&buffer);
  2089. if (err != noErr) {
  2090.     Tcl_AppendResult(interp, "Error finding the file: "", 
  2091.     fileName, "".", NULL);
  2092.     return TCL_ERROR;
  2093. }
  2094. fileRef = FSpOpenResFileCompatTcl(&fileSpec, fsRdPerm);
  2095. if (fileRef == -1) {
  2096.     Tcl_AppendResult(interp, "Error reading the file: "", 
  2097.     fileName, "".", NULL);
  2098.     return TCL_ERROR;
  2099. }
  2100. UseResFile(fileRef);
  2101.     } else {
  2102. /*
  2103.  * The default behavior will search through all open resource files.
  2104.  * This may not be the behavior you desire.  If you want the behavior
  2105.  * of this call to *only* search the application resource fork, you
  2106.  * must call UseResFile at this point to set it to the application
  2107.  * file.  This means you must have already obtained the application's 
  2108.  * fileRef when the application started up.
  2109.  */
  2110.     }
  2111.     /*
  2112.      * Load the resource by name or ID
  2113.      */
  2114.     if (resourceName != NULL) {
  2115. strcpy((char *) rezName + 1, resourceName);
  2116. rezName[0] = strlen(resourceName);
  2117. sourceData = GetNamedResource('scpt', rezName);
  2118.     } else {
  2119. sourceData = GetResource('scpt', (short) resourceNumber);
  2120.     }
  2121.     if (sourceData == NULL) {
  2122. result = TCL_ERROR;
  2123.     } else {
  2124. AEDesc scriptDesc;
  2125. OSAError osaErr;
  2126. scriptDesc.descriptorType = typeOSAGenericStorage;
  2127. scriptDesc.dataHandle = sourceData;
  2128. osaErr = OSALoad(theComponent->theComponent, &scriptDesc,
  2129. kOSAModeNull, resultID);
  2130. ReleaseResource(sourceData);
  2131. if (osaErr != noErr) {
  2132.     result = TCL_ERROR;
  2133.     goto rezEvalError;
  2134. }
  2135. goto rezEvalCleanUp;
  2136.     }
  2137.     rezEvalError:
  2138.     sprintf(idStr, "ID=%d", resourceNumber);
  2139.     Tcl_AppendResult(interp, "The resource "",
  2140.     (resourceName != NULL ? resourceName : idStr),
  2141.     "" could not be loaded from ",
  2142.     (fileName != NULL ? fileName : "application"),
  2143.     ".", NULL);
  2144.     rezEvalCleanUp:
  2145.     if (fileRef != -1) {
  2146. CloseResFile(fileRef);
  2147.     }
  2148.     UseResFile(saveRef);
  2149.     return result;
  2150. }
  2151. /*
  2152.  *----------------------------------------------------------------------
  2153.  *
  2154.  * tclOSAGetScriptID  --
  2155.  *
  2156.  * This returns the context ID, gibven the component name.
  2157.  *
  2158.  * Results:
  2159.  * A standard Tcl result
  2160.  *
  2161.  * Side effects:
  2162.  * Passes out the script ID in the variable scriptID.
  2163.  *
  2164.  *----------------------------------------------------------------------
  2165.  */
  2166. static int 
  2167. tclOSAGetScriptID(
  2168.     tclOSAComponent *theComponent,
  2169.     CONST char *scriptName,
  2170.     OSAID *scriptID) 
  2171. {
  2172.     tclOSAScript *theScript;
  2173.     theScript = tclOSAGetScript(theComponent, scriptName);
  2174.     if (theScript == NULL) {
  2175. return TCL_ERROR;
  2176.     }
  2177.     *scriptID = theScript->scriptID;
  2178.     return TCL_OK;
  2179. }
  2180. /*
  2181.  *----------------------------------------------------------------------
  2182.  *
  2183.  * tclOSAAddScript  --
  2184.  *
  2185.  * This adds a script to theComponent's script table, with the
  2186.  * given name & ID.
  2187.  *
  2188.  * Results:
  2189.  * A standard Tcl result
  2190.  *
  2191.  * Side effects:
  2192.  * Adds an element to the component's script table.
  2193.  *
  2194.  *----------------------------------------------------------------------
  2195.  */
  2196. static int 
  2197. tclOSAAddScript(
  2198.     tclOSAComponent *theComponent,
  2199.     char *scriptName,
  2200.     long modeFlags,
  2201.     OSAID scriptID) 
  2202. {
  2203.     Tcl_HashEntry *hashEntry;
  2204.     int newPtr;
  2205.     static int scriptIndex = 0;
  2206.     tclOSAScript *theScript;
  2207.     if (*scriptName == '') {
  2208. sprintf(scriptName, "OSAScript%d", scriptIndex++);
  2209.     }
  2210.     hashEntry = Tcl_CreateHashEntry(&theComponent->scriptTable,
  2211.     scriptName, &newPtr);
  2212.     if (newPtr == 0) {
  2213. theScript = (tclOSAScript *) Tcl_GetHashValue(hashEntry);
  2214. OSADispose(theComponent->theComponent, theScript->scriptID);
  2215.     } else {
  2216. theScript = (tclOSAScript *) ckalloc(sizeof(tclOSAScript));
  2217. if (theScript == NULL) {
  2218.     return TCL_ERROR;
  2219. }
  2220.     }
  2221.     theScript->scriptID = scriptID;
  2222.     theScript->languageID = theComponent->languageID;
  2223.     theScript->modeFlags = modeFlags;
  2224.     Tcl_SetHashValue(hashEntry,(ClientData) theScript);
  2225.     return TCL_OK;
  2226. }
  2227. /*
  2228.  *----------------------------------------------------------------------
  2229.  *
  2230.  * tclOSAGetScriptID  --
  2231.  *
  2232.  * This returns the script structure, given the component and script name.
  2233.  *
  2234.  * Results:
  2235.  * A pointer to the script structure.
  2236.  *
  2237.  * Side effects:
  2238.  * None
  2239.  *
  2240.  *----------------------------------------------------------------------
  2241.  */
  2242.  
  2243. static tclOSAScript *
  2244. tclOSAGetScript(
  2245.     tclOSAComponent *theComponent,
  2246.     CONST char *scriptName)
  2247. {
  2248.     Tcl_HashEntry *hashEntry;
  2249.     hashEntry = Tcl_FindHashEntry(&theComponent->scriptTable, scriptName);
  2250.     if (hashEntry == NULL) {
  2251. return NULL;
  2252.     }
  2253.     return (tclOSAScript *) Tcl_GetHashValue(hashEntry);
  2254. }
  2255. /*
  2256.  *----------------------------------------------------------------------
  2257.  *
  2258.  * tclOSADeleteScript  --
  2259.  *
  2260.  * This deletes the script given by scriptName.
  2261.  *
  2262.  * Results:
  2263.  * A standard Tcl result
  2264.  *
  2265.  * Side effects:
  2266.  * Deletes the script from the script table, and frees up the
  2267.  * resources associated with it.  If there is an error, then
  2268.  * space for the error message is malloc'ed, and passed out in
  2269.  * the variable errMsg.
  2270.  *
  2271.  *----------------------------------------------------------------------
  2272.  */
  2273. static int
  2274. tclOSADeleteScript(
  2275.     tclOSAComponent *theComponent,
  2276.     CONST char *scriptName,
  2277.     char *errMsg) 
  2278. {
  2279.     Tcl_HashEntry *hashEntry;
  2280.     tclOSAScript *scriptPtr;
  2281.     hashEntry = Tcl_FindHashEntry(&theComponent->scriptTable, scriptName);
  2282.     if (hashEntry == NULL) {
  2283. errMsg = ckalloc(17);
  2284. strcpy(errMsg,"Script not found");
  2285. return TCL_ERROR;
  2286.     }
  2287.     scriptPtr = (tclOSAScript *) Tcl_GetHashValue(hashEntry);
  2288.     OSADispose(theComponent->theComponent, scriptPtr->scriptID);
  2289.     ckfree((char *) scriptPtr);
  2290.     Tcl_DeleteHashEntry(hashEntry);
  2291.     return TCL_OK;
  2292. }
  2293. /*
  2294.  *----------------------------------------------------------------------
  2295.  *
  2296.  * TclOSAActiveProc --
  2297.  *
  2298.  * This is passed to each component.  It is run periodically
  2299.  * during script compilation and script execution.  It in turn
  2300.  * calls Tcl_DoOneEvent to process the event queue.  We also call
  2301.  * the default Active proc which will let the user cancel the script
  2302.  * by hitting Command-.
  2303.  * 
  2304.  * Results:
  2305.  * A standard MacOS system error
  2306.  *
  2307.  * Side effects:
  2308.  * Any Tcl code may run while calling Tcl_DoOneEvent.
  2309.  *
  2310.  *----------------------------------------------------------------------
  2311.  */
  2312.  
  2313. static pascal OSErr 
  2314. TclOSAActiveProc(
  2315.     long refCon)
  2316. {
  2317.     tclOSAComponent *theComponent = (tclOSAComponent *) refCon;
  2318.     Tcl_DoOneEvent(TCL_DONT_WAIT);
  2319.     InvokeOSAActiveUPP(theComponent->defRefCon, theComponent->defActiveProc);
  2320.     return noErr;
  2321. }
  2322. /*
  2323.  *----------------------------------------------------------------------
  2324.  *
  2325.  * ASCIICompareProc --
  2326.  *
  2327.  * Trivial ascii compare for use with qsort.
  2328.  *
  2329.  * Results:
  2330.  * strcmp of the two input strings
  2331.  *
  2332.  * Side effects:
  2333.  * None
  2334.  *
  2335.  *----------------------------------------------------------------------
  2336.  */
  2337. static int 
  2338. ASCIICompareProc(const void *first,const void *second)
  2339. {
  2340.     int order;
  2341.     
  2342.     char *firstString = *((char **) first);
  2343.     char *secondString = *((char **) second);
  2344.     order = strcmp(firstString, secondString);
  2345.     return order;
  2346. }
  2347. #define REALLOC_INCR 30
  2348. /*
  2349.  *----------------------------------------------------------------------
  2350.  *
  2351.  * getSortedHashKeys --
  2352.  *
  2353.  * returns an alphabetically sorted list of the keys of the hash
  2354.  * theTable which match the string "pattern" in the DString
  2355.  * theResult. pattern == NULL matches all.
  2356.  *
  2357.  * Results:
  2358.  * None
  2359.  *
  2360.  * Side effects:
  2361.  * ReInitializes the DString theResult, then copies the names of
  2362.  * the matching keys into the string as list elements.
  2363.  *
  2364.  *----------------------------------------------------------------------
  2365.  */
  2366.  
  2367. static void 
  2368. getSortedHashKeys(
  2369.     Tcl_HashTable *theTable,
  2370.     CONST char *pattern,
  2371.     Tcl_DString *theResult)
  2372. {
  2373.     Tcl_HashSearch search;
  2374.     Tcl_HashEntry *hPtr;
  2375.     Boolean compare = true;
  2376.     char *keyPtr;
  2377.     static char **resultArgv = NULL;
  2378.     static int totSize = 0;
  2379.     int totElem = 0, i;
  2380.     if (pattern == NULL || *pattern == '' || 
  2381.     (*pattern == '*' && *(pattern + 1) == '')) {
  2382. compare = false;
  2383.     }
  2384.     for (hPtr = Tcl_FirstHashEntry(theTable,&search), totElem = 0;
  2385.  hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  2386. keyPtr = (char *) Tcl_GetHashKey(theTable, hPtr);
  2387. if (!compare || Tcl_StringMatch(keyPtr, pattern)) {
  2388.     totElem++;
  2389.     if (totElem >= totSize) {
  2390. totSize += REALLOC_INCR;
  2391. resultArgv = (char **) ckrealloc((char *) resultArgv,
  2392. totSize * sizeof(char *));
  2393.     }
  2394.     resultArgv[totElem - 1] = keyPtr;
  2395.     }
  2396.     Tcl_DStringInit(theResult);
  2397.     if (totElem == 1) {
  2398. Tcl_DStringAppendElement(theResult, resultArgv[0]);
  2399.     } else if (totElem > 1) {
  2400. qsort((VOID *) resultArgv, (size_t) totElem, sizeof (char *),
  2401. ASCIICompareProc);
  2402. for (i = 0; i < totElem; i++) {
  2403.     Tcl_DStringAppendElement(theResult, resultArgv[i]);
  2404. }
  2405.     }
  2406. }
  2407. /*
  2408.  *----------------------------------------------------------------------
  2409.  *
  2410.  * prepareScriptData --
  2411.  *
  2412.  * Massages the input data in the argv array, concating the 
  2413.  * elements, with a " " between each, and replacing n with r,
  2414.  * and \n with "  ".  Puts the result in the the DString scrptData,
  2415.  * and copies the result to the AEdesc scrptDesc.
  2416.  *
  2417.  * Results:
  2418.  * Standard Tcl result
  2419.  *
  2420.  * Side effects:
  2421.  * Creates a new Handle (with AECreateDesc) for the script data.
  2422.  * Stores the script in scrptData, or the error message if there
  2423.  * is an error creating the descriptor.
  2424.  *
  2425.  *----------------------------------------------------------------------
  2426.  */
  2427.  
  2428. static int
  2429. prepareScriptData(
  2430.     int argc,
  2431.     CONST char **argv,
  2432.     Tcl_DString *scrptData,
  2433.     AEDesc *scrptDesc) 
  2434. {
  2435.     char * ptr;
  2436.     int i;
  2437.     char buffer[7];
  2438.     OSErr sysErr = noErr;
  2439.     Tcl_DString encodedText;
  2440.     Tcl_DStringInit(scrptData);
  2441.     for (i = 0; i < argc; i++) {
  2442. Tcl_DStringAppend(scrptData, argv[i], -1);
  2443. Tcl_DStringAppend(scrptData, " ", 1);
  2444.     }
  2445.     /*
  2446.      * First replace the n's with r's in the script argument
  2447.      * Also replace "\n" with "  ".
  2448.      */
  2449.     for (ptr = scrptData->string; *ptr != ''; ptr++) {
  2450. if (*ptr == 'n') {
  2451.     *ptr = 'r';
  2452. } else if (*ptr == '\') {
  2453.     if (*(ptr + 1) == 'n') {
  2454. *ptr = ' ';
  2455. *(ptr + 1) = ' ';
  2456.     }
  2457. }
  2458.     }
  2459.     Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(scrptData),
  2460.     Tcl_DStringLength(scrptData), &encodedText);
  2461.     sysErr = AECreateDesc(typeChar, Tcl_DStringValue(&encodedText),
  2462.     Tcl_DStringLength(&encodedText), scrptDesc);
  2463.     Tcl_DStringFree(&encodedText);
  2464.     if (sysErr != noErr) {
  2465. sprintf(buffer, "%6d", sysErr);
  2466. Tcl_DStringFree(scrptData);
  2467. Tcl_DStringAppend(scrptData, "Error #", 7);
  2468. Tcl_DStringAppend(scrptData, buffer, -1);
  2469. Tcl_DStringAppend(scrptData, " creating Script Data Descriptor.", 33);
  2470. return TCL_ERROR;
  2471.     }
  2472.     return TCL_OK;
  2473. }
  2474. /*
  2475.  *----------------------------------------------------------------------
  2476.  *
  2477.  * tclOSAResultFromID --
  2478.  *
  2479.  * Gets a human readable version of the result from the script ID
  2480.  * and returns it in the result of the interpreter interp
  2481.  *
  2482.  * Results:
  2483.  * None
  2484.  *
  2485.  * Side effects:
  2486.  * Sets the result of interp to the human readable version of resultID.
  2487.  *  
  2488.  *
  2489.  *----------------------------------------------------------------------
  2490.  */
  2491.  
  2492. void 
  2493. tclOSAResultFromID(
  2494.     Tcl_Interp *interp,
  2495.     ComponentInstance theComponent,
  2496.     OSAID resultID )
  2497. {
  2498.     OSErr myErr = noErr;
  2499.     AEDesc resultDesc;
  2500.     Tcl_DString resultStr;
  2501.     Tcl_DStringInit(&resultStr);
  2502.     myErr = OSADisplay(theComponent, resultID, typeChar,
  2503.     kOSAModeNull, &resultDesc);
  2504.     Tcl_DStringAppend(&resultStr, (char *) *resultDesc.dataHandle,
  2505.     GetHandleSize(resultDesc.dataHandle));
  2506.     Tcl_DStringResult(interp,&resultStr);
  2507. }
  2508. /*
  2509.  *----------------------------------------------------------------------
  2510.  *
  2511.  * tclOSAASError --
  2512.  *
  2513.  * Gets the error message from the AppleScript component, and adds
  2514.  * it to interp's result. If the script data is known, will point
  2515.  * out the offending bit of code.  This MUST BE A NULL TERMINATED
  2516.  * C-STRING, not a typeChar.
  2517.  *
  2518.  * Results:
  2519.  * None
  2520.  *
  2521.  * Side effects:
  2522.  * Sets the result of interp to error, plus the relevant portion
  2523.  * of the script.
  2524.  *
  2525.  *----------------------------------------------------------------------
  2526.  */
  2527.  
  2528. void 
  2529. tclOSAASError(
  2530.     Tcl_Interp * interp,
  2531.     ComponentInstance theComponent,
  2532.     char *scriptData )
  2533. {
  2534.     OSErr myErr = noErr;
  2535.     AEDesc errResult,errLimits;
  2536.     Tcl_DString errStr;
  2537.     DescType returnType;
  2538.     Size returnSize;
  2539.     short srcStart,srcEnd;
  2540.     char buffer[16];
  2541.     Tcl_DStringInit(&errStr);
  2542.     Tcl_DStringAppend(&errStr, "An AppleScript error was encountered.n", -1); 
  2543.     OSAScriptError(theComponent, kOSAErrorNumber,
  2544.     typeShortInteger, &errResult);
  2545.     sprintf(buffer, "Error #%-6.6dn", (short int) **errResult.dataHandle);
  2546.     AEDisposeDesc(&errResult);
  2547.     Tcl_DStringAppend(&errStr,buffer, 15);
  2548.     OSAScriptError(theComponent, kOSAErrorMessage, typeChar, &errResult);
  2549.     Tcl_DStringAppend(&errStr, (char *) *errResult.dataHandle,
  2550.     GetHandleSize(errResult.dataHandle));
  2551.     AEDisposeDesc(&errResult);
  2552.     if (scriptData != NULL) {
  2553. int lowerB, upperB;
  2554. myErr = OSAScriptError(theComponent, kOSAErrorRange,
  2555. typeOSAErrorRange, &errResult);
  2556. myErr = AECoerceDesc(&errResult, typeAERecord, &errLimits);
  2557. myErr = AEGetKeyPtr(&errLimits, keyOSASourceStart,
  2558. typeShortInteger, &returnType, &srcStart,
  2559. sizeof(short int), &returnSize);
  2560. myErr = AEGetKeyPtr(&errLimits, keyOSASourceEnd, typeShortInteger,
  2561. &returnType, &srcEnd, sizeof(short int), &returnSize);
  2562. AEDisposeDesc(&errResult);
  2563. AEDisposeDesc(&errLimits);
  2564. Tcl_DStringAppend(&errStr, "nThe offending bit of code was:nt", -1);
  2565. /*
  2566.  * Get the full line on which the error occured:
  2567.  */
  2568. for (lowerB = srcStart; lowerB > 0; lowerB--) {
  2569.     if (*(scriptData + lowerB ) == 'r') {
  2570. lowerB++;
  2571. break;
  2572.     }
  2573. }
  2574. for (upperB = srcEnd; *(scriptData + upperB) != ''; upperB++) {
  2575.     if (*(scriptData + upperB) == 'r') {
  2576. break;
  2577.     }
  2578. }
  2579. Tcl_DStringAppend(&errStr, scriptData+lowerB, srcStart - lowerB);
  2580. Tcl_DStringAppend(&errStr, "_", 1);
  2581. Tcl_DStringAppend(&errStr, scriptData+srcStart, upperB - srcStart);
  2582.     }
  2583.     Tcl_DStringResult(interp,&errStr);
  2584. }
  2585. /*
  2586.  *----------------------------------------------------------------------
  2587.  *
  2588.  * GetRawDataFromDescriptor --
  2589.  *
  2590.  * Get the data from a descriptor.
  2591.  *
  2592.  * Results:
  2593.  * None
  2594.  *
  2595.  * Side effects:
  2596.  * None.
  2597.  *
  2598.  *----------------------------------------------------------------------
  2599.  */
  2600.  
  2601. static void
  2602. GetRawDataFromDescriptor(
  2603.     AEDesc *theDesc,
  2604.     Ptr destPtr,
  2605.     Size destMaxSize,
  2606.     Size *actSize)
  2607.   {
  2608.       Size copySize;
  2609.       if (theDesc->dataHandle) {
  2610.   HLock((Handle)theDesc->dataHandle);
  2611.   *actSize = GetHandleSize((Handle)theDesc->dataHandle);
  2612.   copySize = *actSize < destMaxSize ? *actSize : destMaxSize;
  2613.   BlockMove(*theDesc->dataHandle, destPtr, copySize);
  2614.   HUnlock((Handle)theDesc->dataHandle);
  2615.       } else {
  2616.   *actSize = 0;
  2617.       }
  2618.       
  2619.   }
  2620. /*
  2621.  *----------------------------------------------------------------------
  2622.  *
  2623.  * GetRawDataFromDescriptor --
  2624.  *
  2625.  * Get the data from a descriptor.  Assume it's a C string.
  2626.  *
  2627.  * Results:
  2628.  * None
  2629.  *
  2630.  * Side effects:
  2631.  * None.
  2632.  *
  2633.  *----------------------------------------------------------------------
  2634.  */
  2635.  
  2636. static OSErr
  2637. GetCStringFromDescriptor(
  2638.     AEDesc *sourceDesc,
  2639.     char *resultStr,
  2640.     Size resultMaxSize,
  2641.     Size *resultSize)
  2642. {
  2643.     OSErr err;
  2644.     AEDesc resultDesc;
  2645.     resultDesc.dataHandle = nil;
  2646.     err = AECoerceDesc(sourceDesc, typeChar, &resultDesc);
  2647.     if (!err) {
  2648. GetRawDataFromDescriptor(&resultDesc, (Ptr) resultStr,
  2649. resultMaxSize - 1, resultSize);
  2650. resultStr[*resultSize] = 0;
  2651.     } else {
  2652. err = errAECoercionFail;
  2653.     }
  2654.     if (resultDesc.dataHandle) {
  2655. AEDisposeDesc(&resultDesc);
  2656.     }
  2657.     
  2658.     return err;
  2659. }