home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Information / CSMP Digest / volume 1 / csmp-v1-214.txt < prev    next >
Encoding:
Text File  |  1994-12-08  |  43.2 KB  |  1,076 lines  |  [TEXT/R*ch]

  1. C.S.M.P. Digest             Mon, 16 Nov 92       Volume 1 : Issue 214
  2.  
  3. Today's Topics:
  4.  
  5.     INIT writing 101 (long) [was: Re: little INIT code resource problem]
  6.     scanf equivalent calls that does not use global variables?
  7.     vSynchWait and PowerBook I/O
  8.     Option key madness
  9.     UnloadSeg and pointers to functions
  10.  
  11.  
  12.  
  13. The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
  14.  
  15. The digest is a collection of article threads from the internet newsgroup
  16. comp.sys.mac.programmer.  It is designed for people who read c.s.m.p. semi-
  17. regularly and want an archive of the discussions.  If you don't know what a
  18. newsgroup is, you probably don't have access to it.  Ask your systems
  19. administrator(s) for details.  (This means you can't post questions to the
  20. digest.)
  21.  
  22. Each issue of the digest contains one or more sets of articles (called
  23. threads), with each set corresponding to a 'discussion' of a particular
  24. subject.  The articles are not edited; all articles included in this digest
  25. are in their original posted form (as received by our news server at
  26. cs.uoregon.edu).  Article threads are not added to the digest until the last
  27. article added to the thread is at least one month old (this is to ensure that
  28. the thread is dead before adding it to the digest).  Article threads that
  29. consist of only one message are generally not included in the digest.
  30.  
  31. The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
  32. [128.223.8.8] in the directory /pub/mac/csmp-digest.  Be sure to read the
  33. file /pub/mac/csmp-digest/README before downloading any files.  The most
  34. recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
  35. directory /info-mac/digest/csmp.  If you don't have ftp capability, the sumex
  36. archive has a mail server; send a message with the text '$MACarch help' (no
  37. quotes) to LISTSERV@ricevm1.rice.edu for more information.
  38.  
  39. The digest is also available via email.  Just send a note saying that you
  40. want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
  41. automatically receive each new issue as it is created.  Sorry, back issues
  42. are not available through the mailing list.
  43.  
  44. Send administrative mail to mkelly@cs.uoregon.edu.
  45.  
  46.  
  47. -------------------------------------------------------
  48.  
  49. From: absurd@applelink.apple.com (Tim Dierks, software saboteur)
  50. Subject: INIT writing 101 (long) [was: Re: little INIT code resource problem]
  51. Date: Thu, 15 Oct 1992 02:48:31 GMT
  52. Organization: MacDTS Marauders
  53.  
  54. In article <zocca-141092150341@maria.amc.uva.nl>, zocca@amc.uva.nl (Vincent
  55. Zocca) wrote:
  56. > Hello!
  57. > I've got a probably very little problem with vriting an INIT.
  58. > What I want is to check for disk insert events and perform some action as a
  59. > reaction to them.
  60. > I wrote something that looks like this.
  61. > {-----------------------}
  62. >    {headers and other stuff precede}
  63. >     procedure Main;
  64. >         var
  65. >             INITHndl: handle;
  66. >             OsError: OSErr;
  67. >             myEvent: EventRecord;
  68. >             GotEvent: Boolean;
  69. >     begin
  70. >         INITHndl := GetResource('INIT', 0);
  71. >         DetachResource(INITHndl);
  72. >         repeat
  73. >             GotEvent := WaitNextEvent(DiskMask, myEvent, 60, nil);
  74. >             if GotEvent then
  75. >                 begin
  76. >                     if (HiWord(myevent.message) <> noErr) then
  77. >                         begin
  78. >                             myEvent.where.h := 40;
  79. >                             myEvent.where.v := 20;
  80. >                             InitCursor;
  81. >                             OsError := DIBadMount(myEvent.where, myevent.message);
  82. >    {At this point I want to perform some action}
  83. >                         end;
  84. >                 end;
  85. >         until False;
  86. >     end;
  87. > {-----------------------}
  88. > The code resource generated messes up the machine it's installed on. It
  89. > does get disk events at startup though, I've tested that with a
  90. > SysBeep(10).
  91. > Ok,ok,... What is it? What am I forgetting. Give it to me. I can handle it.
  92.  
  93. Well, OK, if you can handle it....
  94.  
  95. You need to reconsider how INITs generally work on the Mac; this looks
  96. a lot like an application, but nothing like an INIT.  When an INIT is
  97. called, it needs to install itself in some way so it can examine and 
  98. modify the goings on of the Mac, and then it needs to exit.  This INIT
  99. never exits; it just calls WaitNextEvent over and over again.  At that
  100. rate, the Finder will never get launched; the system will spend the
  101. rest of time sitting in your little REPEAT ... UNTIL false; loop looking
  102. for nothing but disk-inserted events.
  103.  
  104. Here's the big secret: you _cannot_ retain control; you've got to find
  105. some way to get control later, when you want to do something. Then, the
  106. only thing your INIT does at INIT time is install the mechanism to get
  107. control later.  Usually, this mechanism is a trap patch; if you patch
  108. a trap, you will get control every time that trap is called; at that
  109. time, you can do what you need to do.  Careful selection of which trap
  110. to patch will make it easy to write clever INITs.
  111.  
  112. For example, let's take your problem.  You want to do something when
  113. a "bad" disk is inserted, after the dialog comes up.  Just for
  114. argument, let's say you want to rename every new disk to "This is a
  115. really new disk!"  One way to do this would be to patch CloseWindow();
  116. you could wait until the "bad mount" dialog got closed and then you
  117. would have control at the right time; just after the bad disk dialog
  118. got dismissed.  This would be a _bad_ way to do this patch, for the
  119. following reasons:
  120.     1) It's going to be a royal pain to be able to tell when the
  121.        bad disk dialog is closing, as opposed to any other window.
  122.     2) CloseWindow only gets passed the WindowPtr to the window to
  123.        close. It might be tough to figure out what disk is the one
  124.        you want to rename (or whatever).
  125.     3) There is no reason 3.
  126.     4) This is real dependant on the way this is all implemented by
  127.        Apple; if they change the way the bad-mount sequence works,
  128.        you'll be in trouble.
  129.     5) You want a trap that will be called at a time when you can
  130.        do what you need to do; for example, if you need to draw
  131.        on the screen, patch a trap that is allowed to move or
  132.        purge memory, because your patch will do so.
  133.  
  134. So the criteria for selecting a trap to patch are: 1) Ideally, it
  135. should be called only at the time when you want to do what you want
  136. to do, or it should be obvious whether you're interested in this call
  137. from the arguments which get passed.  2) The trap should get passed
  138. all the information you're going to need, or you should have a good
  139. way to get everything you need.  3) The trap should be a natural
  140. place to put this code; if you have to stretch to make it work, it's
  141. more and more likely that it won't work properly on future system
  142. software.
  143.  
  144. OK, so what's the best trap to select for your purposes?  Let's list
  145. the criteria again:
  146.    1) We want a trap that is only called when a bad disk is being
  147.       dealt with.
  148.    2) We want a trap which is passed a drive number or volume
  149.       reference number for the disk being mounted, so we can figure
  150.       out which disk to rename.
  151.    3) We want a trap which is essential to the process of mounting
  152.       a bad disk, so we can be sure it's less likely to change
  153.       very much.
  154.    4) Since you can rename a disk at any time, criterion 5), above,
  155.       isn't as important, but it would be best if we did it at
  156.       non-interrupt time, because otherwise we don't want to
  157.       make a synchronous file system call.
  158.  
  159. Given these criteria, I think the obvious choice is DIBadMount();
  160. it's only called when a bad disk is mounted, it gets passed the
  161. drive number in the low word of the event message, it's a crucial
  162. part of the bad-disk process, and it's always called at a "safe"
  163. time, since it can move or purge memory.
  164.  
  165. OK, so we'll now get control when DIBadMount gets called.  We can't,
  166. however, rename the disk yet, because it hasn't yet been mounted;
  167. it's still an unformatted floppy.  We do know, however, know that
  168. it will be formatted and ready to rename when DIBadMount has
  169. finished.  Therefore, we will tail patch it; we'll call the real
  170. DIBadMount near the start of our code and rename the disk when it
  171. returns.
  172.  
  173. The only final stumbling block in our plan is that DIBadMount isn't
  174. really a trap; it is only one routine that shares a single trap,
  175. _Pack2.  This means we need to patch _Pack2, but only do anything
  176. when DIBadMount is called.  The way that the _Pack2 call tells
  177. which one of the Disk Initialization Package calls is being called
  178. is from a selector which is pushed on the stack; specifically,
  179. when an application calls DIBadMount, it first pushes the two
  180. public parameters, the Point where, and the long eventMessage,
  181. and then it pushes a 16-bit word onto the stack with the selector
  182. for which call it is making; in the case of DIBadMount, it
  183. pushes a 2.  Thus, we only want to do anything if the call to
  184. _Pack2 is passing a selector of 2; if it's anything else, we
  185. just want to jump through to the original _Pack2 code and 
  186. forget about it; we're only interested in DIBadMount calls.
  187.  
  188. OK, so here's a description of the entire INIT: (n) indicates
  189. footnote n.
  190.  
  191. INITEntry:
  192.     Detach our code.  (1)
  193.     Get the original address of _Pack2 with GetTrapAddress.
  194.     Remember the original address of _Pack2.  (2)
  195.     Set the address of _Pack2 to point to our routine Pack2Patch
  196.         using SetTrapAddress.
  197.     Return; we're done installing.
  198.  
  199. Pack2Patch:
  200.     Check the selector.
  201.     If the selector does not equal 2:
  202.         Get the original address of _Pack2.
  203.         Jump to it.
  204.     If the selector is equal to 2:
  205.         Remember the drive number which was passed.
  206.         Get the original address of _Pack2.
  207.         Call it.
  208.         If DIBadMount returned an error:
  209.             return the error
  210.         If DIBadMount returned noErr:
  211.             rename the volume, using the drive number you remembered.
  212.             return noErr
  213.  
  214. Footnotes:
  215. (1) Our code needs to be locked and in the system heap; the easiest
  216.     way to do this is to mark the resPreload, resLocked, and resSysHeap
  217.     bits on the INIT resource.  resPreload is important to make sure
  218.     the code gets placed in the best place in the heap.
  219. (2) To remember values like this when you don't have a constant context,
  220.     the best thing to do is use PC-relative storage locations; you
  221.     need to use assembly for this, though (unless you're clever, and
  222.     sicker than I am).  I just posted an example of PC-relative storage
  223.     in an article entitled "Re: Best way to get A5 into VBLTaskProc?".
  224.     (My second post on the subject).  Or, if you're using Think, you
  225.     can use their A4 global stuff.
  226.  
  227. That's about all I have to say (and I think it's plenty).  I haven't
  228. given you remotely enough information to do this completely; most
  229. lacking is a discussion of stack frame management and assembly versus
  230. higher-level languages; you'll have to figure that out for yourself,
  231. or ask for more.
  232.  
  233. Tim Dierks
  234. MacDTS, but I speak too damn much.
  235.  
  236. ---------------------------
  237.  
  238. From: cheng@ee.rochester.edu (Bruce Cheng)
  239. Subject: scanf equivalent calls that does not use global variables?
  240. Date: 4 Oct 92 18:23:47 GMT
  241. Organization: Univ of Rochester, College of Engineering and Applied Science
  242.  
  243. Hi,
  244. I ran into a problem when I tried to parse a binary/ascii mixed data file
  245. for a piece of code that's  to be put into a code resource.  Since I cannot
  246. include any global references in code resource, I cannot use sscanf() (cause`
  247. sscanf() uses some global system state data for buffering???) 
  248.  
  249. Well, is there any suggestion?
  250.  
  251.     -Bruce
  252.  
  253. +-----------------------------------------+------------------------------------+
  254. | Home: 716-475-9329(voice         )      |Usnet: cheng@ee.rochester.edu       |
  255. | Work: 716-427-3475                  |XNS: Bruce_Cheng.Henr801B@xerox.com |
  256. | Address: 222 Norman Road, Rochester     |Uucp: uunet!rochester!ur-val!cheng  |
  257. |          NY14623               |                                    |
  258. +-----------------------------------------+------------------------------------+
  259. - -- 
  260. +-----------------------------------------+------------------------------------+
  261. | Home: 716-271-0960(voice/data/fax)      |Usnet: cheng@ee.rochester.edu       |
  262. | Work: 716-427-6227                  |XNS: Bruce_Cheng.Henr801B@xerox.com |
  263. | Address: 1559 Elmwood Avenue Apt 8      |Uucp: uunet!rochester!ur-val!cheng  |
  264.  
  265. +++++++++++++++++++++++++++
  266.  
  267. From: rmf@chopin.cs.columbia.edu (Robert M. Fuhrer)
  268. Organization: Computer Science Dept., Columbia Univ.
  269. Date: Wed, 7 Oct 1992 21:45:15 GMT
  270.  
  271. Perhaps you can use the format-specific individual calls, such as atoi(),
  272. atof(), and so on? They're also part of the ANSI C standard library.
  273. - --
  274.  
  275. - -- Bob
  276.  
  277. +++++++++++++++++++++++++++
  278.  
  279. From: bwilliam@iat.holonet.net (Bill Williams)
  280. Organization: HoloNet (BBS: 510-704-1058)
  281. Date: Thu, 8 Oct 1992 09:25:54 GMT
  282.  
  283. >"Since I cannot
  284. include any global references in code resource"....
  285.  
  286. I know what you probably mean, but I write code resources all the time
  287. with lots of global references. I use Think C 5.0.3 with globals off of
  288. register a4 using a custom header (so I can call other code segments of
  289. mine back and forth at any point).
  290.  
  291.  
  292. Bill Williams
  293.  
  294.  
  295. +++++++++++++++++++++++++++
  296.  
  297. From: anders@verity.com (Anders Wallgren)
  298. Date: 8 Oct 92 16:17:23 GMT
  299. Organization: Verity, Mountain View, CA, USA
  300.  
  301. In article <RMF.92Oct7164515@chopin.cs.columbia.edu> Robert M.
  302. Fuhrer, rmf@chopin.cs.columbia.edu writes:
  303. >Perhaps you can use the format-specific individual calls, such as
  304. atoi(),
  305. >atof(), and so on? They're also part of the ANSI C standard
  306. library.
  307.  
  308. I think these use globals as well - use the toolbox calls.
  309.  
  310. +++++++++++++++++++++++++++
  311.  
  312. From: rmf@chopin.cs.columbia.edu (Robert M. Fuhrer)
  313. Date: 13 Oct 92 01:52:53 GMT
  314. Organization: Computer Science Dept., Columbia Univ.
  315.  
  316. I just spent a minute touring through the Think C ANSI library source. [I was
  317. thinking perhaps sscanf() might call atof(), which would be a "primitive".]
  318.  
  319. Well, atof() calls strtod(), which in turn calls __vsscanf(). This one calls
  320. the root-level routine __vfscanf(). Unfortunately, that routine, the heart of
  321. scanf(), uses globals to save a bit-vector of any scan-set specified, as well
  322. as a default conversion flag struct. Oh well...
  323. - --
  324.  
  325. - -- Bob
  326.  
  327. +++++++++++++++++++++++++++
  328.  
  329. From: potts@itl.itd.umich.edu (Paul Potts)
  330. Date: 13 Oct 92 02:10:26 GMT
  331. Organization: Instructional Technology Laboratory, University of Michigan
  332.  
  333. In article <RMF.92Oct12205253@chopin.cs.columbia.edu> rmf@chopin.cs.columbia.edu (Robert M. Fuhrer) writes:
  334. >I just spent a minute touring through the Think C ANSI library source. [I was
  335. >thinking perhaps sscanf() might call atof(), which would be a "primitive".]
  336. >
  337. >Well, atof() calls strtod(), which in turn calls __vsscanf(). This one calls
  338. >the root-level routine __vfscanf(). Unfortunately, that routine, the heart of
  339. >scanf(), uses globals to save a bit-vector of any scan-set specified, as well
  340. >as a default conversion flag struct. Oh well...
  341. >--
  342. >
  343. >-- Bob
  344.  
  345. What is it you are trying to do? You can use sscanf() in a code resource
  346. such as an XCMD or whatever. Just include the ANSI-A4 library in your project.
  347. You will have to do the usual A4 stuff. You don't need to access the global
  348. A5 world to use sscanf(). It is a great utility to parse strings sent to
  349. an XCMD for example.
  350.  
  351. Sorry if this is irrelevant... I seem to have missed the start of this thread.
  352.  
  353.  
  354. - -- 
  355. "Everything I say is a lie." <--- potts@oit.itd.umich.edu ---> that's me!
  356. "C++ will make your programming simpler, more efficient, and more fun!"
  357.  
  358. +++++++++++++++++++++++++++
  359.  
  360. From: bpb9204@tamsun.tamu.edu (Brent)
  361. Organization: Texas A&M Univ., Inc.
  362. Date: Tue, 13 Oct 1992 17:18:37 GMT
  363.  
  364. cheng@ee.rochester.edu (Bruce Cheng) writes:
  365. |I ran into a problem when I tried to parse a binary/ascii mixed data file
  366. |for a piece of code that's  to be put into a code resource.  Since I cannot
  367. |include any global references in code resource, I cannot use sscanf() (cause`
  368. |sscanf() uses some global system state data for buffering???) 
  369.  
  370.  
  371. I was needing some sscanf() utility for a program I was writing and I
  372. didn't feel like including the entire ANSI stuff into my project (I know
  373. not all would be linked into the app, but a minimal print would have
  374. doubled the size of the program I was working on).
  375.  
  376. So... I wrote my own implementation of sscanf().  My version works, in
  377. every way but one, just like the original ANSI sscanf().  The bonus in
  378. using this new implementation is that my sscanf() does not rely on anything
  379. else (no __vssssssffssscan() calls) so the code only adds about 3K to your
  380. program, instead of about 10-20K for Think C's ANSI stuff.  Also, no
  381. globals are used, so it'd be safe for SACs.
  382.  
  383. My sscanf() routine works several times faster than Think C's original
  384. version, with the exception of floating point and hex numbers.  Hex numbers
  385. are only slightly faster and the floating point method I used is, ahem, 
  386. slower.  On the other hand, speed improvements of 3-4 times are realized
  387. for integer (short, normal, or long) types and string types.
  388.  
  389. The only difference in the data that my sscanf() function can translate
  390. and the ANSI sscanf() is that my sscanf() does not implement generic
  391. character sets.  Does anybody even use these?   I never have.
  392.  
  393. - -
  394.  
  395. So here is my current status:  sscanf() is about as done as it's going
  396. to get, but I was waiting to release it into the public domain until I
  397. implemented a sprintf() counterpart.  Is there demand for a sscanf() 
  398. function, without the sprintf()?  If there is demand, meaning, if you want a
  399. copy, email me and I'll send out a version to you.
  400.  
  401. The code was written to be freely distributable, usable by anyone for
  402. commercial uses or not. 
  403.  
  404. - -Brent
  405.  
  406. - -- 
  407. - ------------------------------------------------------------------------------
  408. Brent P. Burton, N5VMG                          Department of Computer Science
  409. bpb9204@tamsun.tamu.edu                                   Texas A&M University
  410.       What are typical family values?      Good buys at WalMart.
  411.  
  412. ---------------------------
  413.  
  414. From: jpurlia@qualcomm.com (John Purlia)
  415. Subject: vSynchWait and PowerBook I/O
  416. Date: 13 Oct 92 00:16:40 GMT
  417. Organization: Qualcomm, Inc.
  418.  
  419. I've writted an app that communicates to an external device via the modem
  420. port.  My app runs fine on a Quadra 700 and a IIci, but hangs forever and
  421. ever and ever when run on a PowerBook 170.  A protocol analyzer reveals
  422. that nothing is ever sent from the serial port when I call FSWrite.  When I
  423. trace through the code using MacsBug I find that the code is at the
  424. following:
  425.  
  426. _vSynchWait
  427.     +0000    4080BB8C    MOVE.W $0010(A0),D0
  428.     +0004    4080BB90    *BGT.S    _vSynchWait
  429.  
  430. The value being tested is always 0001, which leads me to believe that I'm
  431. waiting for the asynchronous I/O to complete.  My question...  Why does
  432. this only happen on a PowerBook and what are some of the possibilities for
  433. things I'm doing incorrectly?
  434.  
  435. Thanks!
  436. ...........................................................................
  437. John Purlia          : My brain; not my company's brain.  My brain says...
  438. jpurlia@qualcomm.com : "The Toolbox giveth, and the Tech Notes taketh away"
  439. ...........................................................................
  440.  
  441. +++++++++++++++++++++++++++
  442.  
  443. From: REEKES@applelink.apple.com (Jim Reekes)
  444. Date: 13 Oct 92 19:50:02 GMT
  445. Organization: Apple Computer, Inc.
  446.  
  447. In article <jpurlia-121092170808@129.46.5.45>, jpurlia@qualcomm.com (John
  448. Purlia) wrote:
  449. > I've writted an app that communicates to an external device via the modem
  450. > port.  My app runs fine on a Quadra 700 and a IIci, but hangs forever and
  451. > ever and ever when run on a PowerBook 170.  A protocol analyzer reveals
  452. > that nothing is ever sent from the serial port when I call FSWrite.  When I
  453. > trace through the code using MacsBug I find that the code is at the
  454. > following:
  455. > _vSynchWait
  456. >     +0000    4080BB8C    MOVE.W $0010(A0),D0
  457. >     +0004    4080BB90    *BGT.S    _vSynchWait
  458. > The value being tested is always 0001, which leads me to believe that I'm
  459. > waiting for the asynchronous I/O to complete.  My question...  Why does
  460. > this only happen on a PowerBook and what are some of the possibilities for
  461. > things I'm doing incorrectly?
  462.  
  463. One suggestion.  Don't use FSWrite or FSRead on the serial ports.
  464. FS stands for File System.  They are not designed for any driver calls. 
  465. They might work, but they're not the best approach.
  466.  
  467. - -----------------------------------------------------------------------
  468. Jim Reekes, Polterzeitgeist  |     Macintosh Toolbox Engineering
  469.                              |          Sound Manager Expert
  470. Apple Computer, Inc.         | RAll opinions expressed are mine, and do
  471. 20525 Mariani Ave. MS: 81-KS |   not necessarily represent those of my
  472. Cupertino, CA 95014          |       employer, Apple Computer Inc.S
  473.  
  474. +++++++++++++++++++++++++++
  475.  
  476. From: jpurlia@qualcomm.com (John Purlia)
  477. Organization: Qualcomm, Inc.
  478. Date: Tue, 13 Oct 1992 23:51:42 GMT
  479.  
  480. In article <REEKES-131092125119@90.10.20.67>, REEKES@applelink.apple.com
  481. (Jim Reekes) wrote:
  482. > In article <jpurlia-121092170808@129.46.5.45>, jpurlia@qualcomm.com (John
  483. > Purlia) wrote:
  484. > > 
  485. > > I've writted an app that communicates to an external device via the modem
  486. > > port.  My app runs fine on a Quadra 700 and a IIci, but hangs forever and
  487. > > ever and ever when run on a PowerBook 170.  A protocol analyzer reveals
  488. > > that nothing is ever sent from the serial port when I call FSWrite.  When I
  489. > > trace through the code using MacsBug I find that the code is at the
  490. > > following:
  491. > > 
  492. > > _vSynchWait
  493. > >     +0000    4080BB8C    MOVE.W $0010(A0),D0
  494. > >     +0004    4080BB90    *BGT.S    _vSynchWait
  495. > > 
  496. > > The value being tested is always 0001, which leads me to believe that I'm
  497. > > waiting for the asynchronous I/O to complete.  My question...  Why does
  498. > > this only happen on a PowerBook and what are some of the possibilities for
  499. > > things I'm doing incorrectly?
  500. > One suggestion.  Don't use FSWrite or FSRead on the serial ports.
  501. > FS stands for File System.  They are not designed for any driver calls. 
  502. > They might work, but they're not the best approach.
  503. Filling a parameter block and checking for ioResult not equal to 1 was the
  504. first thing I tried.  Same results, the I/O never completed...
  505.  
  506. But here's the solution!!  :-)
  507.  
  508. I took a look at the supposed status of my I/O prior to writing any data
  509. and discovered the following via a call to SerStatus:
  510.  
  511.         Quadra 700:     0000 0000 0000
  512.         PowerBook 170:  0000 0000 FF00
  513.  
  514. That byte of FF for the PowerBook indicates that the CTS flow control hold
  515. flag is set which meant that I couldn't transmit until it cleared.  Guess
  516. what?  It NEVER clears!  With a call to SerHShake I was able to tell the
  517. serial port to ignore CTS handshaking and evrything works fine as fine can
  518. be!  (But then, I'm only operating at 1200 baud so your proverbial mileage
  519. may very).
  520.  
  521. What does this mean?  Steve Roberts and bis BEHEMOUTH bicycle will soon be
  522. picking up his Internet mail via satellite!!!  Check it out at Interop
  523. everyone!  :-)
  524. ...........................................................................
  525. John Purlia          : My brain; not my company's brain.  My brain says...
  526. jpurlia@qualcomm.com : "The Toolbox giveth, and the Tech Notes taketh away"
  527. ...........................................................................
  528.  
  529. +++++++++++++++++++++++++++
  530.  
  531. From: Bruce.Hoult@bbs.actrix.gen.nz
  532. Date: 14 Oct 92 05:19:36 GMT
  533. Organization: Actrix Information Exchange
  534.  
  535. In article <jpurlia-121092170808@129.46.5.45> jpurlia@qualcomm.com (John Purlia) writes:
  536. > I've writted an app that communicates to an external device via the modem
  537. > port.  My app runs fine on a Quadra 700 and a IIci, but hangs forever and
  538. > ever and ever when run on a PowerBook 170.  A protocol analyzer reveals
  539. > that nothing is ever sent from the serial port when I call FSWrite.
  540.  
  541.  
  542. Every time (yes, it's happend more than once -- some people never
  543. learn :-( ) that one of my serial port programs hangs on a Portable or
  544. PowerBook it's because I've forgotten to call SerHShake to turn off
  545. hardware handshaking.
  546.  
  547. It seems that on most Macs if the HskIn line is unconnected it floats
  548. to the voltage that tells the Mac "carry on" but on the portables it
  549. floats the other way when unconnected...  Hardware handshaking is on
  550. by default.
  551.  
  552. - -- Bruce
  553. - -- 
  554. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  555. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  556. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  557. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  558.  
  559. +++++++++++++++++++++++++++
  560.  
  561. From: John_Miller@mindlink.bc.ca (John Miller)
  562. Date: 14 Oct 92 15:35:30 GMT
  563. Organization: MIND LINK! - British Columbia, Canada
  564.  
  565. In article <REEKES-131092125119@90.10.20.67>, REEKES@applelink.apple.com
  566. (Jim Reekes) wrote:
  567. > One suggestion.  Don't use FSWrite or FSRead on the serial ports.
  568. > FS stands for File System.  They are not designed for any driver calls.
  569. > They might work, but they're not the best approach.
  570.  
  571. :) Well, maybe FS stands for "Fine Stuff", or "Fairly Straightforward"
  572. or "Frank Schultz", but in addition to their reference in the
  573. File Manager chapter, FSRead and FSWrite are also listed in the
  574. Device Manager chapter.  (Inside Mac II pages 178-179) .  They
  575. seem fine for simple use.
  576.  
  577. Of course, seeing as Inside Mac doesn't document a way to
  578. determine if there's room in the serial port output buffer
  579. before calling FSWrite, you might want to use the low
  580. level calls to avoid hanging forever.
  581.  
  582. (I vaguely recall that the old 2 binder version of Inside Mac
  583. didn't mention at all how to read and write to devices:  you had
  584. to have had at least enough of a whiff of UNIX to decide that,
  585. if no Device Manager read/write calls were documented, let's
  586. try the file calls.)
  587.  
  588. ______________________________________________________________________
  589. John Miller                      (604) 433-1795
  590. Symplex Systems                  internet:  john_miller@mindlink.bc.ca
  591. Macintosh Consulting and Software Development
  592. ______________________________________________________________________
  593.  
  594.  
  595. ---------------------------
  596.  
  597. From: wfp@jupiter.claremont.edu (Frank Price)
  598. Subject: Option key madness
  599. Date: 12 Oct 92 04:07:50 GMT
  600. Organization: Harvey Mudd College, Claremont, CA 91711
  601.  
  602. I am trying to read option keys from the Mac keyboard, and of course have  
  603. noticed that various keys will not even send an event when initially typed  
  604. such as Option-E and Option-U, and Option-'.  How do I override this system so  
  605. that Option can be used normally for those special characters?
  606.  
  607. Thanks.
  608.  
  609. - -- Frank
  610. __________________________________________________________________________
  611. Frank Price               | wprice@pomona.claremont.edu
  612.                           | "Nothing crashes like a Macintosh."
  613. NeXTMail appreciated      |      - Guy Kawasaki
  614.  
  615. +++++++++++++++++++++++++++
  616.  
  617. From: leonardr@netcom.com (Leonard Rosenthol)
  618. Date: 12 Oct 92 16:17:45 GMT
  619. Organization: Netcom - Online Communication Services  (408 241-9760 guest)
  620.  
  621. In article <1992Oct12.040750.20383@muddcs.claremont.edu> wprice@pomona.claremont.edu writes:
  622. >I am trying to read option keys from the Mac keyboard, and of course have  
  623. >noticed that various keys will not even send an event when initially typed  
  624. >such as Option-E and Option-U, and Option-'.  How do I override this system so 
  625. >that Option can be used normally for those special characters?
  626. >
  627.     There are two ways to do this - the right way and the wrong way!
  628.  
  629.     The wrong way is what ZTerm & NCSA Telnet (to name two) do it. That is
  630. to require the user to use THEIR KCHR resource, which requires the user to 
  631. do a bit of ResEditting of the System file, since KCHR's must live in the System
  632. under System 7.
  633.  
  634.     The right way to do it (which MicroPhone II & Smartcom do) is to 
  635. first patch _KeyTrans to map the option modiifier to something else (in the
  636. cases above, the control modifieir).  However, since the process manager
  637. swaps patches on even minor context switches, you could STILL get the wrong
  638. characters.  So you have to do some on-the-fly munging of the KCHR (after
  639. copying the orignal!!) - BUT remember to restore the original KCHR on 
  640. suspend/resumes!!
  641.  
  642. - -- 
  643. - -----------------------------------------------------------------------------
  644. Leonard Rosenthol            Internet:     leonardr@netcom.com
  645. Director of Advanced Technology        AppleLink:    MACgician
  646. Aladdin Systems, Inc.            GEnie:        MACgician
  647.  
  648. +++++++++++++++++++++++++++
  649.  
  650. Date: 12 Oct 92 16:38:53 GMT
  651. Organization: Royal Institute of Technology, Stockholm, Sweden
  652.  
  653. > wfp@jupiter.claremont.edu (Frank Price) writes:
  654.  
  655.    noticed that various keys will not even send an event when initially typed  
  656.    such as Option-E and Option-U, and Option-'.  How do I override this system
  657.    so that Option can be used normally for those special characters?
  658.  
  659. They area called dead keys, and option-e, option-u etc are NOT dead
  660. keys on other keyboards (like swedish ones)
  661.  
  662. Try using your own KCHR (the key mapping resource) but make it
  663. an option since peoplr outside the US have different keyboard
  664. needs.
  665.  
  666.  
  667. - -- 
  668.  -- Jon W{tte, h+@nada.kth.se, Mac Hacker Suedoise (not french speaking) --
  669.  
  670.   "From now on I will re-label the EQ on the deck as Fizz and Wobble
  671.    instead of HF and LF."
  672.  
  673. +++++++++++++++++++++++++++
  674.  
  675. From: David.T.Greenfield@dartmouth.edu (David T. Greenfield)
  676. Date: 13 Oct 92 13:47:18 GMT
  677. Organization: Dartmouth College, Hanover, NH
  678.  
  679. In article <1992Oct12.161745.8323@netcom.com>
  680. leonardr@netcom.com (Leonard Rosenthol) writes:
  681.  
  682. >     The wrong way is what ZTerm & NCSA Telnet (to name two) do it. That is
  683. > to require the user to use THEIR KCHR resource, which requires the user to 
  684. > do a bit of ResEditting of the System file, since KCHR's must live in the System
  685. > under System 7.
  686.  
  687. In System 7, KCHRs can be dragged in and out of the system file in the
  688. same manner as fonts, sounds, etc.
  689.  
  690. David
  691. david.t.greenfield@dartmouth.edu
  692.  
  693. +++++++++++++++++++++++++++
  694.  
  695. From: grobbins@Apple.COM (Grobbins)
  696. Date: 13 Oct 92 21:06:28 GMT
  697. Organization: Really Weird Future Mac Department, Apple Computer, Inc.
  698.  
  699. In article <1992Oct12.161745.8323@netcom.com> leonardr@netcom.com (Leonard Rosenthol) writes:
  700. >In article <1992Oct12.040750.20383@muddcs.claremont.edu> wprice@pomona.claremont.edu writes:
  701. >>I am trying to read option keys from the Mac keyboard, and of course have  
  702. >>noticed that various keys will not even send an event when initially typed  
  703. >>such as Option-E and Option-U, and Option-'. How do I override this system so 
  704. >>that Option can be used normally for those special characters?
  705. >
  706. >The wrong way is...
  707. >to require the user to use THEIR KCHR resource, which requires the user to 
  708. >do a bit of ResEditting of the System file, since KCHR's must live in the 
  709. >System under System 7.
  710.  
  711. Not exactly.  Under System 6, using a custom application KCHR is easier
  712. since it can reside in the application's own resource fork.  Just be sure
  713. to set back to the standard system KCHR on suspends and when quitting.
  714.  
  715. While System 7 does require that the KCHR be installed in the System, this
  716. can be done by having the user drag a keyboard file to the System suitcase.
  717. (See Inside Mac VI, page 14-96.)  This is the recommended route, and is
  718. discussed in the Q&A Stack; I'll paste the appropriate entry below.
  719.  
  720. >    The right way to do it (which MicroPhone II & Smartcom do) is to 
  721. >first patch _KeyTrans to map the option modiifier to something else (in the
  722. >cases above, the control modifieir).  However, since the process manager
  723. >swaps patches on even minor context switches, you could STILL get the wrong
  724. >characters.  So you have to do some on-the-fly munging of the KCHR (after
  725. >copying the orignal!!) - BUT remember to restore the original KCHR on 
  726. >suspend/resumes!!
  727.  
  728. Modifying the system KCHR on-the-fly sounds awfully unappealing, as
  729. does searching for certain key combinations in a patch.  A cleaner
  730. patch, one which must be done from an INIT because of the automatic
  731. patch-table swapping that Leonard refers to, would be to set bit 7 of
  732. the keycode parameter to KeyTrans, since dead keys are not processed on
  733. keyups.
  734.  
  735. Grobbins               grobbins@apple.com
  736.  
  737. Usual disclaimers apply.
  738.  
  739. - ---
  740. from the Q&A Stack:
  741.  
  742. I would like to use the Macintosh Option key as the Control key for
  743. keyboards that lack a Control key, such as for Macintosh Plus keyboards. How
  744. can I find the ASCII value that would have been returned if the Option key
  745. weren't pressed, in a way that would be compatible with other keyboards?
  746.  
  747. There are a couple of clean ways to ignore the Option key. One is to
  748. "reprocess" the keyboard event. The fourth byte of the event message is the
  749. ASCII code, but the third byte is the virtual key code. The system calls the
  750. trap KeyTrans to map the virtual key code to ASCII according to a 'KCHR'
  751. resource. You can do the same, and since the high byte of the modifiers are
  752. part of the input to KeyTrans, you can strip out the Option key, call
  753. KeyTrans on the third byte of the event message, and get back the "true"
  754. ASCII keypress. KeyTrans and 'KCHR' resources are documented in Chapter 10
  755. of Inside Macintosh Volume V, Chapter 14 of Inside Macintosh Volume VI
  756. (pages 14-23 and 14-96), and Macintosh Technical Note #160, "Key Mapping."
  757. In Pascal, these steps would look something like:
  758.  
  759.  
  760.     keycode := BAND(event.message, keyCodeMask);{ get virtual code }
  761.     keycode := BSR(keycode, 8); { move to low byte }
  762.     { now combine with modifiers }
  763.     keycode := BOR(keycode, BAND($FF00, event.modifiers));
  764.     keycode := BAND(keycode, $FFFF - optionKey); { strip option }
  765.     newkey := KeyTrans(KCHRHandle^, keyCode, state);
  766.  
  767.  
  768. The resource ID of the current KCHR is available as
  769. GetScript(GetEnvirons(smKeyScript), smScriptKeys). Alternatively, a pointer
  770. to the KCHR data is available under System 7 as GetEnvirons(smKCHRCache), as
  771. discussed in Tech Note #263, "International Canceling."
  772.  
  773. This method may work for you, but there is a possible problem: dead keys.
  774. Since dead keys are processed before your application gets the event, your
  775. application will not see (for example) the first Option-e typed. However,
  776. the dead keys are specified in the 'KCHR' resource, so you can create a KCHR
  777. (ResEdit 2.1.1 includes a template) to omit dead keys (and, if you choose,
  778. option characters) and include it with your application. Call SetScript to
  779. get the system to use your 'KCHR' (see Tech Note #160, IM V-313, and IM VI
  780. 14-40).
  781.  
  782. Another problem is that System 7 ignores a 'KCHR' in the application's
  783. resources, so an application's 'KCHR' has to be installed in the system. You
  784. can install the 'KCHR' with an installer program, or provide a keyboard file
  785. users can drag to the System file. (To create a keyboard file, use ResEdit
  786. to put the 'KCHR' in the System file, and then drag it out with the System 7
  787. Finder.)
  788.  
  789.  
  790. +++++++++++++++++++++++++++
  791.  
  792. From: richardk@kiwi.gen.nz (Richard Knuckey)
  793. Date: 16 Oct 92 05:17:22 GMT
  794. Organization: Unix Usenet Server, Western Springs, Auckland, New Zealand
  795.  
  796.  
  797. >     The wrong way is what ZTerm & NCSA Telnet (to name two) do it. That
  798. > is to require the user to use THEIR KCHR resource, which requires
  799. > the user to  do a bit of ResEditting of the System file, since
  800. > KCHR's must live in the System under System 7.
  801. >     The right way to do it (which MicroPhone II & Smartcom do) is to 
  802. > first patch _KeyTrans to map the option modiifier to something else
  803. > (in the cases above, the control modifieir).  However, since the
  804. > process manager swaps patches on even minor context switches, you
  805. > could STILL get the wrong characters.  So you have to do some
  806. > on-the-fly munging of the KCHR (after copying the orignal!!) - BUT
  807. > remember to restore the original KCHR on  suspend/resumes!!
  808.  
  809.     
  810. No No No! Since when do you have to _patch_ the OS to remap the keyboard.
  811. Never ever patch anything unless you absoulety *have* to.
  812.  
  813. All you do is call _KeyTrans yourself (see Inside Mac V) with your own
  814. KCHR structure in memory. This is what I do in Moria when I detect a
  815. macPlus Keyboard. Code follows:
  816.         
  817.          
  818. /* Variables */
  819.  
  820. extern    Handle    KCHRresource;
  821. extern    long    trans_state;
  822.  
  823.  
  824.  
  825. /* From InitWimp() - Code to set up KCHR and trans_state */
  826.  
  827. if (g->KeyboardType <= envMacPlusKbd)
  828.     {
  829.     trans_state = 0;
  830.     KCHRresource = GetResource('KCHR', 128);
  831.     MoveHHi(KCHRresource);
  832.     HLock(KCHRresource);
  833.     }
  834.  
  835.  
  836.  
  837. /* ------------------------------------------------------------------------
  838.  * RemapKeys
  839.  *
  840.  * This remaps the keyboard using the KCHR we loaded in initwimp.
  841.  * It calls KeyTrans, to translate vitual keycodes to ASCII values.
  842.  * This is only called on keyboards without an Escape
  843.  * or control keys such as on a MacPlus. The KCHR maps the control key
  844.  * to the option key and the tilde key to the escape key. This will work
  845.  * even under system 7.0 since we are forcing a keytranslation instead
  846.  * of simply setting the system wide KCHR, which under system 7.0 requires
  847.  * the KCHR resource to be in the system for reasons discussed in
  848.  * Inside Macintosh VI pp 14-96
  849.  */
  850.  
  851. RemapKeys(theEvent)
  852. EventRecord *theEvent;
  853.     {
  854.     short   keycode;
  855.     char    *p, *q;     /* used for byte level acces to variables */
  856.     long    ascii_code;
  857.     
  858.     p = &keycode;
  859.     
  860.     q = &theEvent->message;
  861.     p[1] = q[2];
  862.     
  863.     q = &theEvent->modifiers;
  864.     p[0] = q[0];
  865.     
  866.     ascii_code = KeyTrans(*KCHRresource,keycode,&trans_state);
  867.     
  868.     p = &ascii_code;
  869.     theEvent->message = p[3];
  870.     }
  871.  
  872.  
  873. /* From Window Handler for main Moria game window */
  874.  
  875. case keyDown:
  876. case autoKey:
  877.     ObscureCursor();
  878.     if (g->KeyboardType <= envMacPlusKbd)
  879.         RemapKeys ( theEvent );
  880.     
  881.     theChar = (char)(theEvent->message & charCodeMask);
  882.     
  883.  
  884. The Biggest advantages of this way is that it doesn't muck around with
  885. the rest of the system, It only remaps the keyboard for the window
  886. that needs it, I doesn't require the instalation of any resources to the
  887. system file and the KCHR does't show up in the Keyboard menu.
  888.  
  889. A disadvantage is that the system does not pass on "dead keys" to you. this
  890. means that you won't get an option-e passed to you, since it's marked as a dead
  891. key in the default US system KCHR. This may casue you concern. Luckely Moria
  892. doesn't use any on these keys anyway :-). The only clean way around this
  893. second problem if you absoluetly MUST have option-e mapped to something is yo
  894. havethe user install a keyboard layout, and for you to switch to that layout on
  895. resume events ,and to set it back on suspend events.
  896.  
  897.  
  898. ---------------------------
  899.  
  900. From: sll2@cunixa.cc.columbia.edu (Steven L Levitt)
  901. Subject: UnloadSeg and pointers to functions
  902. Organization: Columbia University
  903. Date: Thu, 15 Oct 1992 18:19:40 GMT
  904.  
  905.     If I have a structure on the heap which contains a point
  906. function and I call UnloadSeg() on the segment which contains that 
  907. function, will the pointer still be valid afterward?  I would like to call
  908. UnloadSeg() each time through the main event loop, but I don't know if the Jump
  909. Table scheme the mac employes will preserve the validity of my f
  910. pointers.
  911.  
  912. - ----------------
  913. Steven L. Levitt  sll2@cunixa.cc.columbia.edu
  914. An Undergrad
  915.  
  916.  
  917. +++++++++++++++++++++++++++
  918.  
  919. From: keith@taligent.com (Keith Rollin)
  920. Organization: Taligent
  921. Date: Thu, 15 Oct 1992 23:24:43 GMT
  922.  
  923. In article <1992Oct15.181940.2146@news.columbia.edu>,
  924. sll2@cunixa.cc.columbia.edu (Steven L Levitt) wrote:
  925. >     If I have a structure on the heap which contains a point
  926. > function and I call UnloadSeg() on the segment which contains that 
  927. > function, will the pointer still be valid afterward?  I would like to call
  928. > UnloadSeg() each time through the main event loop, but I don't know if the Jump
  929. > Table scheme the mac employes will preserve the validity of my f
  930. > pointers.
  931.  
  932. The pointer should remain valid. If you take the address of a function, the
  933. compiler will generate a jump table entry for that function. The function
  934. pointer will then, in fact, point to the jump table entry.
  935.  
  936. - -----
  937. Keith Rollin
  938. Phantom Programmer
  939. Taligent, Inc.
  940.  
  941. +++++++++++++++++++++++++++
  942.  
  943. From: absurd@applelink.apple.com (Tim Dierks, software saboteur)
  944. Date: Thu, 15 Oct 1992 22:24:22 GMT
  945. Organization: MacDTS Marauders
  946.  
  947. In article <1992Oct15.181940.2146@news.columbia.edu>,
  948. sll2@cunixa.cc.columbia.edu (Steven L Levitt) wrote:
  949. >     If I have a structure on the heap which contains a point
  950. > function and I call UnloadSeg() on the segment which contains that 
  951. > function, will the pointer still be valid afterward?  I would like to call
  952. > UnloadSeg() each time through the main event loop, but I don't know if the Jump
  953. > Table scheme the mac employes will preserve the validity of my f
  954. > pointers.
  955. > ----------------
  956. > Steven L. Levitt  sll2@cunixa.cc.columbia.edu
  957. > An Undergrad
  958.  
  959. The answer: usually.  There are two different ways to construct a function
  960. address, whether you're calling it or taking its address for later use.
  961. You can either use the address in the jump table, which is constant and
  962. doesn't move, or you can take the actual pointer to the code, which,
  963. because it's in a code segment, could plausibly be unloaded and move
  964. (unless it's in the same segment as your main entry point).  So if
  965. you're going to build a pointer to a function, you have three options:
  966.  
  967. 1) Make sure the function is in the main segment.
  968. 2) If it's not in the main segment, make sure the segment it's in
  969.    never gets unloaded while the function pointer is supposed to
  970.    be valid.
  971. 3) Make sure you get a jump table pointer.
  972.  
  973. 3) is best, except for functions which might be called at interrupt
  974. time, such as VBL tasks; for these, 1) is best, because you won't be
  975. able to load the segment when the function gets called.  Usually,
  976. this isn't a problem; by default, both Think and MPW give you jump
  977. table function pointers.  You're guaranteed of getting a jump table
  978. pointer if you take the routine's address from another segment, because
  979. that's all the code in that area knows; for example, if I take the
  980. address of function foo() which is in the segment FooSeg from function
  981. bar() in BarSeg, I'll be guaranteed a jump table address.  Even if
  982. the function and the code getting the address are in the same segment,
  983. you will almost always get a jump table address.  There are two
  984. exceptions:
  985.  
  986. 1) If using the -b or -b3 options in MPW C, or if you're not using
  987.    the -b option in MPW Pascal, you will get a PC-relative
  988.    function address if the source and destination are in the
  989.    same segment.
  990. 2) If you're using -model far, you'll always get a PC-relative
  991.    address due to a bug in the way it patches up your segment.
  992.  
  993. Thus, if you want to be sure your address will always be OK and it's
  994. not in the main segment, either take the address from another
  995. segment or don't use the -b or -b3 option for MPW C and do use
  996. the -b option in MPW Pascal.
  997.  
  998. I'm sure there are similar things for Think, but I don't know what
  999. they are.
  1000.  
  1001. Tim Dierks
  1002. MacDTS, but I post too much
  1003.  
  1004. +++++++++++++++++++++++++++
  1005.  
  1006. From: phils@chaos.cs.brandeis.edu (Phil Shapiro)
  1007. Date: 16 Oct 92 02:45:00 GMT
  1008. Organization: Symantec Corp.
  1009.  
  1010. In article <absurd-151092151115@seuss.apple.com> absurd@applelink.apple.com (Tim Dierks, software saboteur) writes:
  1011.  
  1012.    [ Tim explains MPW C & Pascal's rules for creating jump table entries
  1013.     and associated options. ]
  1014.  
  1015.    I'm sure there are similar things for Think, but I don't know what
  1016.    they are.
  1017.  
  1018. THINK C will always produce a jump table entry for functions whose
  1019. address is taken, even if the reference is intra-segment and/or the
  1020. function is declared static. I believe THINK Pascal follows the same
  1021. rule.
  1022.  
  1023. The only exception to the above rule is for single-segment code
  1024. resources, who don't have a jump table anyway.
  1025.  
  1026.     -phil
  1027. - --
  1028.    Phil Shapiro                                   Software Engineer
  1029.    Language Products Group                     Symantec Corporation
  1030.            Internet: phils@cs.brandeis.edu
  1031.  
  1032. +++++++++++++++++++++++++++
  1033.  
  1034. From: Anders Wallgren <anders@verity.com>
  1035. Organization: Verity, Mountain View, CA, USA
  1036. Date: Fri, 16 Oct 92 02:18:21 GMT
  1037.  
  1038. In article <absurd-151092151115@seuss.apple.com> Tim Dierks,
  1039. absurd@applelink.apple.com writes:
  1040. >2) If you're using -model far, you'll always get a PC-relative
  1041. >   address due to a bug in the way it patches up your segment.
  1042.  
  1043. This is fixed in the latest MPW on ETO.
  1044.  
  1045. ---------------------------
  1046.  
  1047. End of C.S.M.P. Digest
  1048. **********************
  1049.