home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / hc / xcmd_glu.sit / XCMD.HowToUse < prev    next >
Text File  |  1987-08-06  |  10KB  |  233 lines

  1. XCMD and XFCN: The Magic Hooks That Extend HyperTalk
  2.  
  3.     This documentation by Ted Kaehler, 1 August 1987
  4.     For HyperCard 1.0.  (Works with internal versions 1.0B9 and later.)
  5.     ⌐Apple Computer, Inc. 1987
  6.     All Rights Reserved.
  7.  
  8. Dan Winkler has created an interface that allows powerful new commands 
  9. to be added to HyperCard "in the field."  When a command in a script 
  10. cannot be found, HyperCard looks for a resource of type XCMD with 
  11. the same name as the unknown command.  Likewise, when a function cannot
  12. be found, HyperCard looks for a resource of type XFCN.  Consider XCMDs
  13. and XFCNs to be extensions of stack scripts.  Whenever a handler (for a 
  14. command or function) is not found in a stack script, HyperCard
  15. immediately looks for a XCMD or XFCN in that stack.  The total 
  16. inheritance order is: Button (or Field), Card, Stack, stack XCMD, Home,
  17. home XCMD, XCMD in HyperCard application file, HyperCard command.  An 
  18. XCMD or XFCN is a code resource with no header bytes (just like a desk 
  19. accessory).  You can move them from file to file with ResEdit or with 
  20. any other resource moving tool.
  21.  
  22. The only thing passed into an XCMD or XFCN is a pointer to a XCmdBlock.  
  23. It looks like this:
  24.  
  25.   XCmdPtr = ^XCmdBlock;
  26.   XCmdBlock =
  27.     RECORD
  28.       paramCount:  INTEGER;                  { the number of arguments }
  29.       params:      ARRAY[1..16] OF Handle;   { the arguments }
  30.       returnValue: Handle;                   { the result of this XCMD }
  31.       passFlag:    BOOLEAN;                  { pass the message on? }
  32.  
  33.       entryPoint:  ProcPtr;                  { call back to HyperCard }
  34.       request:     INTEGER;                  { what you want to do }
  35.       result:      INTEGER;                  { the answer it gives }
  36.       inArgs:      ARRAY[1..8] OF LongInt;   { args XCMD sends HyperCard }
  37.       outArgs:     ARRAY[1..4] OF LongInt;   { answer HyperCard sends back }
  38.     END;
  39.  
  40. You read the agruments (they are handles to zero terminated strings), 
  41. do whatever the purpose of this XCMD is, and optionally store a 
  42. result into returnValue.  All data values going to and from HyperTalk 
  43. are zero-terminated ASCII strings.
  44.  
  45. Resources of type XCMD are commands, and resourcs of type XFCN are 
  46. fuctions that return a value.  If you store a result string into 
  47. returnValue in a command, the user can get it by asking for "the result"
  48. (useful for explaining why there was an error).  In a function, you are
  49. expected to store the answer into returnValue.  If you don't store 
  50. anything, the result is the empty string.
  51.  
  52. If passFlag is false (the normal case), this XCMD or XFCN has handled the 
  53. message and the script resumes execution.  If passFlag is true, HyperCard
  54. searches the remaining inheritance chain for another handler or
  55. XCMD with the same name.  This is just like the "pass" control structure
  56. in a script.
  57.  
  58. The file Flash.p is an example XCMD.  It takes one argument which is 
  59. the ASCII characters for a decimal integer.  It inverts the screen 
  60. twice the number of times indicated.  It is meant to be used as a command 
  61. and puts an error string into "the result" if the argument is odd.
  62.  
  63. Peek.p is a function (XFCN) that returns the value of any memory location 
  64. in the machine (purists avert your eyes).
  65.  
  66.  
  67. The second part of the XCmdBlock record has to do with 
  68. calling HyperCard back in the middle of your code to ask a question.
  69. If you wanted to manage the call to HyperCard yourself, you would 
  70. fill inArgs with your arguments, put a request code in request,
  71. and JSR to the address in entryPoint.  HyperCard returns the values you
  72. requested in outArgs and a reslut code in result.
  73.   
  74. However, Dan Winkler has packaged the entire range of calls on HyperCard,
  75. so that if you are using Pascal, you can simply call a procedure.  Both 
  76. Peek and Flash use some conversion routines that Dan has kindly
  77. supplied.  The file XCmdGlue.inc has the glue procedures.  Handle is always
  78. a handle to a zero-terminated string.  If a handle is returned, you are
  79. responsible for disposing it.  The calls are:
  80.  
  81. PROCEDURE SendCardMessage(msg: Str255);
  82. {  Send a HyperCard message (a command with arguments) to the current card. }
  83.  
  84. FUNCTION EvalExpr(expr: Str255): Handle;
  85. {  Evaluate a HyperCard expression and return the answer.  The answer is
  86.    a handle to a zero-terminated string. }
  87.  
  88. FUNCTION StringLength(strPtr: Ptr): LongInt;
  89. {  Count the characters from where strPtr points until the next zero byte. 
  90.    Does not count the zero itself.  strPtr must be a zero-terminated string.  }
  91.  
  92. FUNCTION StringMatch(pattern: Str255; target: Ptr): Ptr;
  93. { Perform case-insensitive match looking for pattern anywhere in
  94.   target, returning a pointer to first character of the first match,
  95.   in target or NIL if no match found.  pattern is a Pascal string,
  96.   and target is a zero-terminated string. }
  97.  
  98. PROCEDURE ZeroBytes(dstPtr: Ptr; longCount: LongInt);
  99. {  Write zeros into memory starting at destPtr and going for longCount 
  100.    number of bytes. }
  101.  
  102. FUNCTION PasToZero(str: Str255): Handle;
  103. {  Convert a Pascal string to a zero-terminated string.  Returns a handle
  104.    to a new zero-terminated string.  The caller must dispose the handle.
  105.    You'll need to do this for any result or argument you send from 
  106.    your XCMD to HyperTalk. }
  107.  
  108. PROCEDURE ZeroToPas(zeroStr: Ptr; VAR pasStr: Str255);
  109. {  Fill the Pascal string with the contents of the zero-terminated
  110.    string.  You create the Pascal string and pass it in as a VAR 
  111.    parameter.  Useful for converting the arguments of any XCMD to 
  112.    Pascal strings.}
  113.  
  114. FUNCTION StrToLong(str: Str31): LongInt;
  115. {  Convert a string of ASCII decimal digits to an unsigned long integer. }
  116.  
  117. FUNCTION StrToNum(str: Str31): LongInt;
  118. {  Convert a string of ASCII decimal digits to a signed long integer.
  119.    Negative sign is allowed.  }
  120.  
  121. FUNCTION StrToBool(str: Str31): BOOLEAN;
  122. {  Convert the Pascal strings 'true' and 'false' to booleans. }
  123.  
  124. FUNCTION StrToExt(str: Str31): Extended;
  125. {  Convert a string of ASCII decimal digits to an extended long integer. }
  126. VAR x: Extended;
  127.  
  128. FUNCTION LongToStr(posNum: LongInt): Str31;
  129. {  Convert an unsigned long integer to a Pascal string.  }
  130.  
  131. FUNCTION NumToStr(num: LongInt): Str31;
  132. {  Convert a signed long integer to a Pascal string.  }
  133.  
  134. FUNCTION NumToHex(num: LongInt; nDigits: INTEGER): Str31;
  135. {  Convert an unsigned long integer to a hexadecimal number and put it
  136.    into a Pascal string.  }
  137.  
  138. FUNCTION BoolToStr(bool: BOOLEAN): Str31;
  139. {  Convert a boolean to 'true' or 'false'.  }
  140. VAR str: Str31;
  141.  
  142. FUNCTION ExtToStr(num: Extended): Str31;
  143. {  Convert an extended long integer to decimal digits in a string.  }
  144.  
  145. FUNCTION GetGlobal(globName: Str255): Handle;
  146. {  Return a handle to a zero-terminated string containing the value of 
  147.    the specified HyperTalk global variable.  }
  148.  
  149. PROCEDURE SetGlobal(globName: Str255; globValue: Handle);
  150. {  Set the value of the specified HyperTalk global variable to be
  151.    the zero-terminated string in globValue.  The contents of the 
  152.    Handle are copied, so you must still dispose it afterwards.  }
  153.  
  154. FUNCTION GetFieldByName(cardFieldFlag: BOOLEAN; fieldName: Str255): Handle;
  155. {  Return a handle to a zero-terminated string containing the value of 
  156.    field fieldName on the current card.  You must dispose the handle.  }
  157.  
  158. FUNCTION GetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: INTEGER): Handle;
  159. {  Return a handle to a zero-terminated string containing the value of 
  160.    field fieldNum on the current card.  You must dispose the handle.  }
  161.  
  162. FUNCTION GetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER): Handle;
  163. {  Return a handle to a zero-terminated string containing the value of 
  164.    the field whise ID is fieldID.  You must dispose the handle.  }
  165.  
  166. PROCEDURE SetFieldByName(cardFieldFlag: BOOLEAN; fieldName: Str255; fieldVal: Handle);
  167. {  Set the value of field fieldName to be the zero-terminated string 
  168.    in fieldVal.  The contents of the Handle are copied, so you must 
  169.    still dispose it afterwards.  }
  170.  
  171. PROCEDURE SetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: INTEGER; fieldVal: Handle);
  172. {  Set the value of field fieldNum to be the zero-terminated string 
  173.    in fieldVal.  The contents of the Handle are copied, so you must 
  174.    still dispose it afterwards.  }
  175.  
  176. PROCEDURE SetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER; fieldVal: Handle);
  177. {  Set the value of the field whose ID is fieldID to be the zero-
  178.    terminated string in fieldVal.  The contents of the Handle are 
  179.    copied, so you must still dispose it afterwards.  }
  180.  
  181. FUNCTION StringEqual(str1,str2: Str255): BOOLEAN;
  182. {  Return true if the two strings have the same characters.  
  183.    Case insensitive compare of the strings.  }
  184.  
  185. PROCEDURE ReturnToPas(zeroStr: Ptr; VAR pasStr: Str255);
  186. {  zeroStr points into a zero-terminated string.  Collect the 
  187.    characters from there to the next carriage Return and return 
  188.    them in the Pascal string pasStr.  If a Return is not found, 
  189.    collect chars until the end of the string. }
  190.  
  191. PROCEDURE ScanToReturn(VAR scanPtr: Ptr);
  192. {  Move the pointer scanPtr along a zero-terminated 
  193.    string until it points at a Return character
  194.    or a zero byte.  }
  195.  
  196. PROCEDURE ScanToZero(VAR scanPtr: Ptr);
  197. {  Move the pointer scanPtr along a zero-terminated 
  198.    string until it points at a zero byte.  }
  199.  
  200.  
  201.  
  202. Here are the files you will need:
  203.  
  204.  HyperXCmd.p
  205.  XCmdGlue.inc
  206.  Flash.p  (An example command to see how everything is really done.)
  207.  Peek.p   (An example function to see how everything is really done.)
  208.  
  209. Here are the typical MPW commands for compiling an XCMD
  210.  
  211.     pascal -w PioneerLVP4200.p
  212.     link -m ENTRYPOINT -o Video -rt XCMD=15 -sn Main=PioneerLVP4200 ╢
  213.       PioneerLVP4200.p.o "{MPW}"Libraries:interface.o
  214.  
  215. Video is the stack that MPW will install the XCMD in.  If you don't use 
  216. any of the routines in interface.o, its just
  217.  
  218.     pascal Flash.p
  219.     link -o HyperCommands -rt XCMD=0 -sn Main=Flash Flash.p.o
  220.  
  221. After executing these, use ResEdit to move the XCMD or XFCN to the 
  222. proper stack.
  223.  
  224. For "C" programmers, the author has provided a defintion (HyperXCmd.h) and
  225. an include file (XCmdGlue.inc.c) and an example (CFlash.c).
  226.  
  227. Breakpoints do not appear to work in XCMDs, but putting a debugger call
  228. in your code does work.  In addition, saying:
  229.  
  230.    hd 'h'
  231.  
  232. in MacsBug allows you to find your resource in memory by seeing its name
  233. and location in the listing.