home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Information / Programming / Mac Programming FAQ / Mac Programming FAQ 2⁄3 < prev    next >
Encoding:
Text File  |  1994-12-08  |  28.9 KB  |  788 lines  |  [TEXT/R*ch]

  1. *4* Files
  2.  
  3. 4.1) Q: How do I tell fopen() to open a file the user has selected using 
  4. StandardGetFile?
  5.  
  6. A: The "standard" ANSI C file functions are less than well suited for 
  7. the Macintosh way of doing things.  However, if you are doing a port for 
  8. your own enjoyment and benefit (or maybe for in-house work) you can use 
  9. the following function: (see below about converting a wdRefNum into a 
  10. vRefNum/parID pair)
  11.  
  12. *code*
  13. FILE *
  14. fopen_mac ( short vRefNum , long parID , char * fileName , char * mode ) {
  15.  
  16. short oldVol ;
  17. short aVol ;
  18. long aDir , aProc ;
  19. FILE * ret = NULL ;
  20.  
  21.    if ( GetVol ( NULL , & oldVol ) ) {
  22.       return NULL ;
  23.    }
  24.    if ( GetWDInfo ( oldVol , & aVol , & aDir , & aProc ) ) {
  25.       return NULL  ;
  26.    }
  27.    if ( HSetVol ( NULL , vRefNum , parID ) ) {
  28.       return NULL ;
  29.    }
  30.    ret = fopen ( fileName , mode ) ;
  31.    if ( HSetVol ( NULL, aVol , aDir ) ) {
  32.       /* an error we can't currently handle */
  33.    }
  34.    if ( SetVol ( NULL, oldVol ) ) {
  35.       /* an error we can't currently handle */
  36.    }
  37.    return ret ;
  38. }
  39. *end*
  40.  
  41. All of the above is necessary for one reason or another - if you are 
  42. interested, by all means look HSetVol up in Think Reference 2.0 or New 
  43. Inside Mac: Files.
  44.  
  45. In older versions of MPW; this wouldn't work since the MPW libraries 
  46. used to do a GetVol and explicitly use that value by itself.
  47.  
  48. 4.2) Q: When can I use the HOpen, HCreate etc file calls? Are they only 
  49. System 7 calls?
  50.  
  51. A: All the HXxx calls that take a vRefNum and parID as well as the file 
  52. name are implemented in glue that works on any system that has HFS 
  53. (meaning 3.2 and up with the HD20 INIT, and all systems from System 6 
  54. and up)
  55.  
  56. The glue is available in MPW 3.2 and up, and Think C 5.0 and up.  This 
  57. goes for all HXxx calls except HOpenDF; therefore, if you are interested 
  58. in System 6 compatibility, use HOpen instead and make sure you don't 
  59. allow file names beginning with a period.
  60.  
  61. 4.3) Q: Why do you say wdRefNum sometimes and vRefNum sometimes? 
  62. Why do you say parID sometimes and dirID sometimes? 
  63.  
  64. A: When the Mac first made an appearance in 1984, it identified files by 
  65. using a vRefNum (volume reference number meaning a floppy disk or later 
  66. hard disk) and a name.  Once HFS saw the light of day, folders within 
  67. folders became a reality, and you needed a dirID as well to point out 
  68. what folder you really meant on the volume.  However, older programs 
  69. that weren't being rewritten still knew nothing about directory IDs, so 
  70. Apple had SFGetFile make up "fake" vRefNums that didn't just specify a 
  71. volume, but also a parent folder.  These are called wdRefNums (for 
  72. working directory) and were a necessary evil invented in 1985.  You 
  73. should not create (or, indeed, use) wdRefNums yourself.
  74.  
  75. There is a system-wide table that maps wdRefNums onto vRefNum/parID 
  76. pairs.  There is a limit to the size of this table.  A dirID and a parID 
  77. is almost the same thing; you say "parID" when you mean the folder 
  78. something is in, while you say a "dirID" when you mean the folder 
  79. itself.  If you for instance have a folder called "Foo" with a folder 
  80. called "Bar" in it, the parID for "Bar" would be the dirID for "Foo."
  81.  
  82. 4.4) Q: How do I convert a wdRefNum as returned by SFGetFile 
  83. into a vRefNum/parID pair to use with the HXxx calls?
  84.  
  85. A: Use GetWDInfo, which is declared as: 
  86.  
  87. Pascal OSErr GetWDInfo ( short wdRefNum , short * vRefNum , long * parID 
  88. , OSType * procID ) ;
  89.  
  90. The procID parameter must be non-NULL and point to an OSType variable, 
  91. but the value of that variable can and should be ignored.
  92.  
  93. It is recommended that, as soon as you get your hands on a wdRefNum, for 
  94. instance from SFGetFile, you directly convert it into a vRefNum/parID 
  95. pair and always use the latter to reference the folder.
  96.  
  97. 4.5) Q: How do I select a folder using SFGetFile? 
  98.  
  99. A: This requires a custom dialog with a filter proc.  It is too 
  100. complicated to show here, but not totally impossible to comprehend.  
  101. There is sample code on ftp.apple.com, in the directory dts/snippets, on 
  102. how to do this.
  103.  
  104. 4.6) Q: How do I get the full path of a file referenced by a vRefNum, 
  105. parID and name?
  106.  
  107. A: You don't. 
  108.  
  109. OK, I cheated you.  There is exactly ONE valid reason to get the full 
  110. path of a file (or folder, for that matter) and that is to display its 
  111. location to the user in, say, a settings dialog.  To actually save the 
  112. location of the file you should do this: (assuming the file is in an 
  113. FSSpec called theFile - you can use FSSpecs in your program even if you 
  114. don't run under System 7; just make your own MyFSMakeFSSpec that fills 
  115. in the FSSpec manually if it's not implemented)
  116.  
  117. *code*
  118. if ( ! aliasManagerAvailable ) { /* System 6 ? */
  119.    GetVolumeName ( theFile -> vRefNum , vName ) ;
  120.    GetVolumeModDate ( vRefNum , & date ) ;
  121.    Save ( vName , date , parID , fileName ) ;
  122. } else {
  123.    NewAlias ( NULL , theFile , & theAlias ) ;
  124.    Save ( theAlias ) ;
  125.    DisposeHandle ( ( Handle ) theAlias ) ;
  126. }
  127. *end*
  128.  
  129. If you are really concerned about these issues (of course you are!) you 
  130. should save BOTH of these methods when available, and load back whatever 
  131. is there that you can handle; since users may be using your application 
  132. in a mixed System 6/System 7 environment.
  133.  
  134. To get back to the file is left as an exercise for the reader. 
  135.  
  136. To open a file using fopen() or the Pascal equivalent, see above about 
  137. using and not using HSetVol.
  138.  
  139. 4.7) Q: What about actually getting the full path for a file? I promise 
  140. I will only use it to show the location of a file to the user!
  141.  
  142. A: Enter PBGetCatInfo, the Vegimatic of the Mac file system.  Any Mac 
  143. hacker of knowledge has taken this system call to his heart.  What you 
  144. do is this:
  145.  
  146. *code*
  147. OSErr
  148. GetFolderParent ( FSSpec * fss , FSSpec * parent ) {
  149.  
  150. CInfoPBRec rec ;
  151. short err ;
  152.  
  153.    * parent = * fss ;
  154.    rec . hFileInfo   . ioNamePtr = parent -> name ;
  155.    rec . hFileInfo   . ioVRefNum = parent -> vRefNum ;
  156.    rec . hFileInfo   . ioDirID = parent -> parID ;
  157.    if ( parent -> name [ 0 ] ) {
  158.       rec . hFileInfo . ioFDirIndex = 0 ;
  159.    } else {
  160.       rec . hFileInfo . ioFDirIndex = -1 ;
  161.    }
  162.    rec . hFileInfo   . ioFVersNum = 0 ;
  163.    err = PBGetCatInfoSync ( & rec ) ;
  164.    if ( ! ( rec . hFileInfo . ioFlAttrib & 0x10 ) ) { /* Not a folder */
  165.       if ( ! err ) {
  166.          err = dirNFErr ;
  167.       }
  168.    } else {
  169.       parent -> parID = rec . dirInfo . ioDrParID ;
  170.       parent -> name [ 0 ] = 0 ;
  171.    }
  172.    return err ;
  173. }
  174.  
  175.  
  176. OSErr
  177. GetFullPathHandle ( FSSpec * fss , Handle * h ) {
  178.  
  179. Handle  tempH = NULL ;
  180. short err ;
  181. FSSpec fs = * fss ;
  182.  
  183.    while ( fs . parID > 1 ) {
  184.       tempH = NULL ;
  185.       PtrToHand ( & fs . name [ 1 ] , & tempH , fs . name [ 0 ] ) ;
  186.       PtrAndHand ( ( void * ) ":" , tempH , 1 ) ;
  187.       HandAndHand ( * h , tempH ) ;
  188.       SetHandleSize ( * h , 0L ) ;
  189.       HandAndHand ( tempH , * h ) ;
  190.       DisposeHandle ( tempH ) ;
  191.       tempH = NULL ; 
  192.       GetFolderParent ( & fs , & sSpec ) ;
  193.       fs = sSpec ;
  194.    }
  195.    GetVolName ( fs   . vRefNum , fs . name ) ;
  196.    PtrToHand ( & fs . name [ 1 ] , & tempH , fs . name [ 0 ] ) ;
  197.    PtrAndHand ( ( void * ) ":" , tempH , 1 ) ;
  198.    HandAndHand ( * h , tempH ) ;
  199.    SetHandleSize ( * h , 0L ) ;
  200.    HandAndHand ( tempH , * h ) ;
  201.    DisposeHandle ( tempH ) ;
  202.    tempH = NULL ;
  203.    if ( ! IsFolder ( fss ) ) {
  204.    SetHandleSize ( * h , GetHandleSize ( * h ) - 1 ) ; // Remove colon }
  205.    return 0 ;
  206. }
  207. *end*
  208.  
  209. 4.8) Q: So how do I get the names of the files in a directory? 
  210.  
  211. A: You use PBGetCatInfo again, but this time you set ioFDirIndex to 1 or 
  212. more (you need to know the dirID and vRefNum of the
  213.  
  214. folder you're interested in) You then call PBGetCatInfoSync for values 
  215. of ioFDirIndex from 1 and up, until you get an fnfErr.  Any other err 
  216. means you are not allowed to get info about THAT item, but you may be 
  217. for the next.  Then collect the names in the string you made ioNamePtr 
  218. point to as you go along.  Note that you need to fill in the ioDirID 
  219. field for each iteration through the loop, and preferrably clear the 
  220. ioFVersNum as well.
  221.  
  222. Note that the contents of a directory may very well change while you are 
  223. iterating over it; this is most likely on a file server that more than 
  224. one user uses, or under System 7 where you run Personal File Share.
  225.  
  226. 4.9) Q: How do I find the name of a folder for which I only know the 
  227. dirID and vRefNum?
  228.  
  229. A: You call (surprise!) PBGetCatInfo! Make ioNamePtr point to an empty 
  230. string (but NOT NULL) of length 63 (like, an Str63) and ioFDirIndex 
  231. negative (-1 is a given winner) - this makes PBGetCatInfo return 
  232. information about the vRefNum/dirID folder instead of the file/folder 
  233. specified by vRefNum, parID and name.
  234.  
  235. 4.10) Q: How do I make the Finder see a new file that I created? Or if I 
  236. changed the type of it; how do I display a new icon for it?
  237.  
  238. A: You call (surprise!) PBGetCatInfo followed by PBSetCatInfo for the 
  239. FOLDER the file is in.  Inbetween, you should set ioDrMdDat to the 
  240. current date&time.  Code:
  241.  
  242. *code*
  243. OSErr
  244. TouchFolder ( short vRefNum , long parID ) {
  245.  
  246. CInfoPBRec rec ;
  247. Str63 name ;
  248. short err ;
  249.  
  250.    rec . hFileInfo . ioNamePtr = name ;
  251.    name [ 0 ] = 0 ;
  252.    rec . hFileInfo . ioVRefNum = vRefNum ;
  253.    rec . hFileInfo . ioDirID = parID ;
  254.    rec . hFileInfo . ioFDirIndex = -1 ;
  255.    rec . hFileInfo . ioFVersNum = 0 ;
  256.    err = PBGetCatInfoSync ( & rec ) ;
  257.    if ( err ) {
  258.       return err ;
  259.    }
  260.    GetDateTime ( & rec . dirInfo . ioDrMdDat ) ;
  261.    rec . hFileInfo . ioVRefNum = vRefNum ;
  262.    rec . hFileInfo . ioDirID = parID ;
  263.    rec . hFileInfo . ioFDirIndex = -1 ;
  264.    rec . hFileInfo . ioFVersNum = 0 ;
  265.    rec . hFileInfo . ioNamePtr [ 0 ] = 0 ;
  266.    err = PBSetCatInfoSync ( & rec ) ;
  267.    return err ;
  268. }
  269. *end*
  270.  
  271. 4.11) Q: Aren't we done with PBGetCatInfo soon? 
  272.  
  273. A: Well, it turns out that you can also find out whether an FSSpec is a 
  274. file or a folder by calling PBGetCatInfo and check bit 4 (0x10) of 
  275. ioFlAttr to see whether it is a folder.  You may prefer to call 
  276. ResolveAliasFile for this instead.
  277.  
  278. You can also check the script of the file's title using PBGetCatInfo and 
  279. check the ioFlFndrXInfo field if you want to work with other script 
  280. systems than the Roman system.
  281.  
  282. Another common use is to find out how many items are in a folder; the 
  283. modification date of something or the correct capitalization of its name 
  284. (since the Mac file system is case independent BUT preserves the case 
  285. the user uses)
  286.  
  287. 4.12) Q: How do I set what folder should initially be shown in the 
  288. SFGetFile boxes?
  289.  
  290. A: You stuff the dirID you want to show into the lo-mem global 
  291. CurDirStore, and the NEGATIVE of the vRefNum you want into the lo-mem 
  292. global SFSaveDisk.
  293.  
  294. If you are using CustomGetFile and return sfSelectionChanged from an 
  295. "init" message handler, you must remember to clear the script code, else 
  296. the selection will not change.
  297.  
  298. 4.13) Q: How do I find the folder my application started from? How do I 
  299. find the application file that's running?
  300.  
  301. A: Under System 7, you call GetProcessInformation using the 
  302. ProcessSerialNumber kCurrentProcess with a pointer to an existing FSSpec 
  303. in the parameter block.  This will give you your file, and, by using the 
  304. vRefNum and parID, the folder the application is in.
  305.  
  306. *code*
  307. OSErr CurrentProcessLocation(FSSpec *applicationSpec)
  308. {
  309.    ProcessSerialNumber currentPSN;
  310.    ProcessInfoRec info;
  311.    
  312.    currentPSN.highLongOfPSN = 0;
  313.    currentPSN.lowLongOfPSN = kCurrentProcess;
  314.    info.processInfoLength = sizeof(ProcessInfoRec);
  315.    info.processName = NULL;
  316.    info.processAppSpec = applicationSpec;
  317.    return ( GetProcessInformation(¤tPSN, &info) );
  318. }
  319. *end*
  320.  
  321. Beware from writing to your applications resource or data forks; the 
  322. former breaks on CDs/write protected floppies/file servers/virus 
  323. checkers, the latter fails on PowerPC as well as in the above cases.
  324.  
  325. 4.14) Q: When can I use those nifty, easy to use FSSpec calls?
  326.  
  327. A: In Systems >= 7, in System 6 with QuickTime installed, in any system 
  328. if you use the FSpCompat functions provided by MoreFiles [see below].
  329.  
  330. 4.15) Q: I need to use 
  331.  
  332. *5* Imaging with QuickDraw and the Gang
  333.  
  334. 5.1) Q: Why is CopyBits so slow? 
  335.  
  336. A: It is not.  It just requires some hand-holding to get good results.  
  337. The main rules are: Make sure the source and destination pixMaps are of 
  338. the same depth.
  339.  
  340. Make sure the front color is black and the back color is white.
  341.  
  342. Use srcCopy and don't use a masking region, unless it's rectangular. 
  343.  
  344. Copy to an unclipped window (the frontmost window).  Make sure the 
  345. ctSeed values of the source pixMap and dest pixMap match. 
  346.  
  347. Copying few and large pixMaps is faster than copying many and small 
  348. ones.  Icon-sized sprites count as small ones.
  349.  
  350. Make sure your source bitmap or pixelMap has the same alignment, when 
  351. adjusted for the source and destination rect expressed in global screen 
  352. coordinates.  The necessary alignment is 32 bits (4 bytes), although 128 
  353. bit (16 byte) alignment is probably even better on 68040 macs and won't 
  354. hurt on other macs.
  355.  
  356. Example of global alignment: 
  357.  
  358. Your window is positioned at (42,100) (H,V) 
  359.  
  360. Your destination rectangle is (10,20)-(74,52) 
  361.  
  362. The alignment coefficient of the rectangle in global coordinates is 
  363. (42+10)*bitDepth where bitDepth is one of 1,2,4,8,16 or 32.
  364.  
  365. Make sure your source pixmap rect has the same coeffecient modulo your 
  366. alignment factor (in bits) For black&white macs, this is still true, 
  367. although bitDepth is fix at 1.  Offscreen pixMaps can calculate with a 
  368. "global posistion" of 0,0 and get correct results.
  369.  
  370. 5.2) Q: Why is CopyBits still too slow? 
  371.  
  372. A: Because there is always some overhead involved in calling QuickDraw; 
  373. you have the trap dispatcher, clipping checks, and checking whether the 
  374. CopyBits call is being recorded in a PICT handle (if you called 
  375. OpenPicture)
  376.  
  377. If you can't live with this, look at 4.8 below, but PLEASE try and make 
  378. CopyBits work, and retain the CopyBits code in your application, so 
  379. users with special monitors (accellerator cards, PowerBook color 
  380. screens, Radius Pivot screens) can still play your game.  (non-game 
  381. applications don't need more speed than CopyBits can give at its max.  
  382. Promise!)
  383.  
  384. 5.3) Q: What is the fastest way to set one pixel? 
  385.  
  386. A: NOT SetCPixel()! Assuming you have the correct ForeColor() set, you 
  387. can set the pen size to (1,0) and call Line (0,1)
  388.  
  389. I have heard PaintRect is good for this but requires slightly more code.  
  390. Using PaintRect eliminates a trap call.
  391.  
  392. 5.4) Q: Why do pictures I record suddenly draw as empty space or not 
  393. draw at all?
  394.  
  395. A: When recording pictures, you have to set the clipping area to exactly 
  396. the frame of the picture you are recording.  This is because it is 
  397. initally set at -32768,32727 in both directions, and offsetting the 
  398. picture even one pixel when drawing it will result in the region 
  399. wrapping around and becoming empty.
  400.  
  401. When recording pictures, do this: 
  402.  
  403. *code*
  404. PicHandle h = OpenPicture ( & theRect ) ;
  405. ClipRect ( & theRect ) ;
  406.    /* draw the picture */
  407. ClosePicture ( ) ;
  408. *end*
  409.  
  410. 5.5) Q: Where can I find the format of picture files and 
  411. resources? 
  412.  
  413. A: The format of a picture resource version 1 is defined in a 
  414. technical note. This format is obsolete. 
  415.  
  416. The format of a picture resource version 2 is defined in Old Inside Mac 
  417. vol V, with addenda in Old Inside Mac vol VI.
  418.  
  419. Some things happen with QuickTime compressed pictures; try the Inside 
  420. Mac: QuickTime book or turn to Inside Mac: Imaging with QuickDraw which 
  421. is the definite reference on QuickDraw.
  422.  
  423. The format of a picture file is the same as that of a picture resource 
  424. with 512 added 0 bytes in front.
  425.  
  426. 5.6) Q: GWorlds? 
  427.  
  428. A: What about them? They're great.  Look them up in Old Inside Mac vol 
  429. VI.  Don't forget to SetGWorld back to what it was before calling 
  430. WaitNextEvent.
  431.  
  432. 5.7) Q: How do I find the current depth of the screen? 
  433.  
  434. A: My question to you is: What screen? Many macs have more than one 
  435. screen attached.  You can use GetDeviceList and walk the devices to find 
  436. the screen you're looking for (use TestDeviceAttribute to see whether 
  437. it's a screen) or you can call GetMaxDevice() to find the deepest device 
  438. your window intersects.
  439.  
  440. Once you have the device handle, finding the depth is just a 
  441. matter of looking at the gdPMap pixMapHandle, and dereference it 
  442. to the pmSize field. Done. 
  443.  
  444. 5.8) Q: Why is it a bad idea to draw directly to screen? 
  445.  
  446. A: Because of several reasons: 
  447.  
  448. - You will be incompatible with future display hardware. 
  449.  
  450. - You will be incompatible with some present-day display 
  451. hardware, such as Radius Pivots and PowerBook color screens. 
  452.  
  453. - You have to think about a lot of things; testing it all on 
  454. your own machine is not possible and the chances of crashing are 
  455. great. 
  456.  
  457. - You will be incompatible with future hardware where devices 
  458. may live in some unaccessible I/O space. 
  459.  
  460. 5.9) Q: But I really need to do it. I can't make my animation 
  461. into a QuickTime movie, and CopyBits is too slow, even when 
  462. syncing to the screen retrace. 
  463.  
  464. A: You have to prepare yourself, and ask these questions: 
  465.  
  466. 1) Do I want to support all screens, or just 8-bit devices? 
  467.  
  468. 2) Do I have a few weeks of free time to make it work? 
  469.  
  470. 3) Do I want to get nasty mail when I break on some hardware and 
  471. have to rev the application - even if I may not be able to get 
  472. ahold of the hardware that makes it break? 
  473.  
  474. If all you're doing is rendering an image pixel-by-pixel or 
  475. line-by-line, maybe you can draw directly into an offscreen 
  476. pixMap/GWorld and then CopyBits the entire GWorld to screen? 
  477. That will be more compatible, especially if you use the 
  478. keepLocal flag when creating the GWorld. 
  479.  
  480. 5.10) Q: Okay, so how do I get the base address of the screen? 
  481.  
  482. A: "The" screen? Which screen? There may be several. The base 
  483. address may be on an accellerated screen card. There may be more 
  484. than one screen covering the same desktop area. 
  485.  
  486. Due to unfortunate circumstances, there is a bug in 
  487. GetPixBaseAddr() that causes it to return incorrect results for 
  488. early versions of System 7. Instead, get the baseAddr directly 
  489. from the gdPMap handle of the GDHandle for the screen you draw 
  490. to. This address may need switching to 32bit mode to be valid. 
  491.  
  492. 5.11) Q: Quit stalling and give me code! 
  493.  
  494. A: Okay, but I'll let you sweat over Inside Mac to figure out 
  495. what it does. All of it is important; believe me! To make this 
  496. code run faster, a lot of the things it does can be done once 
  497. before starting to draw. 
  498.  
  499. Make sure that you have a window that covers the area where you 
  500. are drawing, so other windows will not be overdrawn. Also make 
  501. sure that you do not do direct-to-screen-drawing while you are 
  502. in the background. 
  503.  
  504. *code*
  505. /* This is presently untested code */
  506. /* Value is dependent on what depth the screen has */
  507. /* This code doesn't work on non-color-quickdraw Macs (i e the MacClassic) */
  508. /* "where" is in GLOBAL coordinates */
  509. void
  510. SetPixel ( Point where , unsigned long value ) {
  511.  
  512. Rect r ;
  513. GDHandle theGD ;
  514. char * ptr ;
  515. long rowBytes ;
  516. short bitsPerPixel ;
  517. PixMapHandle pmh ;
  518. Boolean oldMode ;
  519.  
  520.    r . left = where . h ;
  521.    r . top = where   . v ;
  522.    r . right = r . left + 1 ;
  523.    r . bottom = r . top + 1 ;
  524.    theGD = GetMaxDevice ( & r ) ;
  525.    if ( theGD ) {
  526.       where . v -= ( * theGD ) -> gdRect . left ;
  527.       where . h -= ( * theGD ) -> gdRect . top ;
  528.       pmh = ( * theGD ) -> gdPMap ;
  529.       rowBytes = ( ( * pmh ) -> rowBytes ) & 0x3fff ;
  530.       ptr = ( char * ) ( * pmh ) -> baseAddr ;
  531.       bitsPerPixel = ( * pmh ) -> pixelSize ;
  532.       oldMode = true32b ;
  533.       ptr += where . v * rowBytes ;
  534.       SwapMMUMode ( & oldMode ) ;
  535.       switch ( bitsPerPixel ) {
  536.       case 1 :
  537.          if ( value & 1 ) { 
  538.             ptr [ where . h >> 3 ] |= ( 128 >> ( where . h & 7 ) ) ;
  539.          } else {
  540.             ptr [ where . h >> 3 ] &= ~( 128 >> ( where . h & 7 ) ) ;
  541.          }
  542.          break ;
  543.       case 2 :
  544.          ptr [ where . h >> 2 ] &= ( 192 >> 2 * ( where . h & 3 ) ) ;
  545.          ptr [ where . h >> 2 ] |= ( value & 3 ) << 2 * ( 3 - ( where . h
  546. & 3 ) ) ;
  547.          break ;
  548.       case 4 :
  549.          ptr [ where . h >> 1 ] &= ( where . h & 1 ) ? 0xf : 0xf0 ;
  550.          ptr [ where . h >> 1 ] |= ( value & 15 ) << 4 * ( 1 - ( where . h
  551. & 1 ) ) ;
  552.          break ;
  553.       case 8 :
  554.          ptr [ where . h ] = value ;
  555.          break ;
  556.       case 16 :
  557.          ( ( unsigned short * ) ptr ) [ where . h ] = value ;
  558.          break ;
  559.       case 32 :
  560.          ( ( unsigned long * ) ptr ) [ where . h ] = value ;
  561.          break ;
  562.       default :
  563.          abort ( ) ; /* Should never get here */
  564.       }
  565.       SwapMMUMode ( & oldMode ) ;
  566.    }
  567. }
  568. *end*
  569.  
  570. *6* Text
  571.  
  572. 6.1) Q: How do I get TextEdit to display more than 32k of text?
  573.  
  574. A: You don't.  Truly, it's not worth it.  There's a call-for-call 
  575. TextEdit replacement called TE32k which does > 32k text, and is 
  576. available from any recent Info-Mac mirror.  It doesn't do styled text, 
  577. though.
  578.  
  579. 6.2) Q: How do I get TextEdit to display more than 32k of __styled__ 
  580. text *and* embedded objects in the text (such as pictures)?
  581.  
  582. WASTE, available at ftp://ghost.dsi.unimi.it/pub2/papers/piovanel, is a 
  583. vast improvement over TextEdit.  Version 1.0 does >32k styled text 
  584. retains compatibility with the TextEdit style scrap (which is used to 
  585. store styled text in files such as SimpleText's, as well as in the 
  586. clipboard), includes source code and is freeware.  Really worth the 
  587. download.  Version 1.1 adds embedded objects within the text, such as 
  588. pictures, intelligent cut-and-paste, built-in Drag Manager support.  1.1 
  589. is currently in alpha, but seems to be very stable.
  590.  
  591. 6.3) Q: How do I include pictures in text using TextEdit?
  592.  
  593. A: There's no really easy way (such as a TEAddPict() call), and it will 
  594. be a nasty looking kludge if you do get it working, but if you can live 
  595. with that, here's how to do it.  I do recommend that you take a look 
  596. at Q 6.2, above.
  597.  
  598. Write an algorithm to get the position of a special marker character 
  599. [Teach/SimpleText uses option-space] or text attribute that the user 
  600. will insert wherever he wants a picture.  Pass this position to a 
  601. function similar to the one below.
  602.  
  603. *code* 
  604. /*
  605.    TEDrawPicture
  606.    Draw a picture within TextEdit's text.
  607.    
  608.    input:
  609.       pos - the position of the special character in the text where the user 
  610.             wants a picture.
  611.       r  - size of picture
  612.    
  613.    output:
  614.       r  - frame in which picture was drawn
  615. */
  616.  
  617. void TEDrawPicture(short pos,PicHandle pic,Rect &r,TEHandle theTE)
  618. {
  619.    Point bottomLeft; //could be topleft, or whatever you want
  620.    
  621.    bottomLeft=TEGetPoint(pos,theTE);
  622.    
  623.    r.right=bottomLeft.h+(r.right-r.left);
  624.    r.top=bottomLeft.v-(r.bottom-r.top);
  625.    r.left=bottomLeft.h;
  626.    r.bottom=bottomLeft.v;
  627.    
  628.    DrawPicture(pic,&r);
  629. }
  630.  
  631. *end*
  632.  
  633. I'll leave selection and hiliting as an exercise for the reader.
  634.  
  635. Thereotically, it should be possible to kludge up TextEdit to the point 
  636. where it would treat pictures as if they were actually letters (rather big 
  637. letters, but letters just the same).  That's what the width and word break 
  638. hooks are for, after all.  However, this would be a lot of Work, and I've 
  639. never seen it done.  One is lead to believe that it's less work to create 
  640. an improved version of TextEdit from the ground up with picture support.  
  641. One could probably modify WASTE for this purpose, since the source is 
  642. available.
  643.  
  644. 6.4) Q: I have all this money, and I want to get rid of it. How do I
  645. edit more than 32k of styled text now?
  646.  
  647. A: There are at least two solutions.
  648.  
  649. 1) The Galaxy application framework comes with a styled text editting
  650. engine which does more than 32k of text. It also happens to support
  651. cross-platform application development. Pricing starts at $10000.
  652. <galaxy@visix.com>
  653.  
  654. 2) DataPak has a library called "PAIGE" in the works, and you can
  655. buy a late beta of it. It is written to be customizable to any extent,
  656. and you can do _anything_ in it (want quicktime movies that play and
  657. flow with the text while editting? Three pages of code; you can adapt
  658. their picture sample code.) Available for Mac, Windows and Power Mac.
  659. Pricing at $5000 ($25000 for source code) - it might be cheaper if
  660. you talk to them.
  661.  
  662. *7* Communications and Networking
  663.  
  664. 7.1) Q: How do I get at the serial ports? 
  665.  
  666. A: You call OpenDriver for the names "\p.AOut" and "\p.AIn" to get at 
  667. the modem port, and "\p.BOut" and "\p.BIn" for the printer port.  The 
  668. function RAMSDOpen was designed for the original Mac with 128 kB of 
  669. memory and 64 kB of ROM, and has been extinct for several years.
  670.  
  671. However, many users use their serial ports for MIDI, LocalTalk, graphic 
  672. tablets, or what have you and have installed an additional serial port 
  673. card to get more ports.  What you SHOULD do as a good application is to 
  674. use the Comm Toolbox Resource Manager to search for serial resources; 
  675. this requires that the Comms Toolbox is present (true on earlier System 
  676. 6 with an INIT, on later System 6 and System 7 always, as well as on 
  677. A/UX) and that you have initialized the comms resource manager.  The 
  678. exact code follows (adapted from Inside Mac Comms Toolbox):
  679.  
  680. *code*
  681. #include <CommResources.h>
  682. OSErr
  683. FindPorts ( Handle * portOutNames , Handle * portInNames , Handle * names
  684. , Handle * iconHandles ) {
  685.  
  686. OSErr ret = noErr ;
  687. short old = 0 ;
  688. CRMRec theCRMRec , * found ;
  689. CRMSerialRecord * serial ;
  690.  
  691.    * portOutNames = NewHandle ( 0L ) ;
  692.    * portInNames = NewHandle ( 0L ) ;
  693.    * names = NewHandle ( 0L ) ;
  694.    * iconHandles = NewHandle ( 0L ) ;
  695.    while ( ! ret ) {
  696.       theCRMRec . crmDeviceType = crmSerialDevice ;
  697.       theCRMRec . crmDeviceID = old ;
  698.       found = ( CRMRec * ) CRMSearch ( ( QElementPtr ) & theCRMRec ) ;
  699.       if ( found ) {
  700.          serial = ( CRMSerialRecord * ) found -> crmAttributes ;
  701.          old = found -> crmDeviceID ;
  702.          PtrAndHand ( & serial -> outputDriverName , * portOutNames ,
  703.             sizeof ( serial -> outputDriverName ) ) ;
  704.          PtrAndHand ( & serial -> inputDriverName , * portInNames ,
  705.             sizeof ( serial -> inputDriverName ) ) ;
  706.          PtrAndHand ( & serial -> name , * names , 
  707.             sizeof ( serial -> name ) ) ;
  708.          PtrAndHand ( & serial -> deviceIcon , * iconHandles ,
  709.             sizeof ( serial -> deviceIcon ) ) ;
  710.       } else {
  711.          break ;
  712.       }
  713.    }
  714.    return err ;
  715. }
  716. *end*
  717.  
  718. This will create four handles with the driver names, device names and 
  719. driver icon handles for all of the available serial devices.  Then let 
  720. the user choose with a pop-up menu or scrolling list, and save the 
  721. choice in your settings file.
  722.  
  723. You can use OpenDriver, SetReset, SetHShake, SetSetBuf, SerGetBuf and 
  724. the other Serial Manager functions on these drivers.  To write to the 
  725. serial port, use FSWrite for synchronous writes that wait until all is 
  726. written, or PBWrite asynchronously for queuing up data that is supposed 
  727. to go out but you don't want to wait for it.  At least once each time 
  728. through your event loop, you should call SerGetBuf on the in driver 
  729. reference number you got from OpenDriver, and call FSRead for that many 
  730. bytes - neither more nor less.
  731.  
  732. If you are REALLY interested in doing the right thing, you will use the 
  733. Communications Toolbox Connection Manager instead; this will give you 
  734. access to modems, direct lines, and networks of various kinds using the 
  735. same API! Great for stuff like BBSes that may be on a network as well 
  736. etc.  The Comms Toolbox also priovides modularized terminal emulation 
  737. and file transfer tools, although the Apple-suplied VT102 tool is pretty 
  738. lame, as is the VT102 mode of the VT320 tool.
  739.  
  740. 7.2) Q: Where is a Berkley sockets library for the Mac? 
  741.  
  742. A: There are some problems with that.  MacTCP, the Mac Toolbox 
  743. implementation of TCP/IP, doesn't have an API that looks at all like 
  744. Berkley sockets.  For instance, there is ONE paramater-block call to do 
  745. a combined listen()/accept()/bind() - sort of.  I have heard that there 
  746. may be a socket library available by ftp from MIT but haven't seen it 
  747. myself.
  748.  
  749. There is also a pretty good C++ TCP implementation called GUSI which is 
  750. easily handled, and it also is callable from C using the Berkley socket 
  751. API.  Apart from TCP, it also handles "standard" Mac network protocols 
  752. such as ADSP.  The big disadvantage is that it is currently only 
  753. implemented for MPW.  The ftp site is nic.switch.ch, 
  754. software/mac/src/mpw_c.
  755.  
  756. I can also recommend the Communications Toolbox; for the price of using 
  757. an API that is a bigger pain in the ass than using Windoze, you get the 
  758. benefit of being able to use any kind of connection (TCP tools are 
  759. available).
  760.  
  761. Novell and Wollogong offer commercial socket-like libraries. 
  762.  
  763. 7.3) Q: Where do I find MacTCP? 
  764.  
  765. A: You can buy the MacTCP developers kit from APDA.  It is also 
  766. available on E T O, and if you want saner headers than those, try ftp to 
  767. seeding.apple.com.  MacTCP (the control panel) is included with System 
  768. 7.5 and above.
  769.  
  770. 7.4) Q: I'm trying to write to the serial port.  It works fine on the 
  771. following Machines, Quadra700, IIFX, Powerbook 170, Quadra 840av, but 
  772. freezes on the Duo 230 and 280c.
  773.  
  774. A: You need to call SerHShake.  Otherwise you get screwed on some 
  775. machines without a hardware handshaking cable because the port default to 
  776. hardware handshaking.
  777.  
  778. --------------------comp.sys.mac.programmer.info---------------------
  779. comp.sys.mac.programmer.info  is  primarily  for  distributing  FAQs,
  780. tutorials, news, and  similar  documents  related to programming  the
  781. Macintosh.  To post, email csmp_info@xplain.com
  782. -----------------------about MacTech Magazine----------------------
  783. PO Box 250055, Los Angeles, CA 90025, 310-575-4343, Fax:310-575-0925
  784. For more info, anonymous ftp to ftp.netcom.com and cd to /pub/xplain
  785. or email to the following @xplain.com : custservice, editorial, 
  786. adsales, marketing, accounting, pressreleases, progchallenge, 
  787. publisher, info
  788.