From: pottier@clipper.ens.fr (Francois Pottier) Subject: csmp-digest-v3-049 Date: Mon, 8 Aug 1994 16:13:56 +0200 (MET DST) C.S.M.P. Digest Mon, 08 Aug 94 Volume 3 : Issue 49 Today's Topics: CODE resources 101 Can I do this with the Thread Manager? Dice Rolling - answers Easy file access functions [source] How to detect whether Debugger is installed? Q: Converting PB to FSSpec Q: Reentrancy and PowerMac Runtime Model Std filter proc trashes register D3! Which NIM for serial port info? The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier (pottier@clipper.ens.fr). The digest is a collection of article threads from the internet newsgroup comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi- regularly and want an archive of the discussions. If you don't know what a newsgroup is, you probably don't have access to it. Ask your systems administrator(s) for details. If you don't have access to news, you may still be able to post messages to the group by using a mail server like anon.penet.fi (mail help@anon.penet.fi for more information). Each issue of the digest contains one or more sets of articles (called threads), with each set corresponding to a 'discussion' of a particular subject. The articles are not edited; all articles included in this digest are in their original posted form (as received by our news server at nef.ens.fr). Article threads are not added to the digest until the last article added to the thread is at least two weeks old (this is to ensure that the thread is dead before adding it to the digest). Article threads that consist of only one message are generally not included in the digest. The digest is officially distributed by two means, by email and ftp. If you want to receive the digest by mail, send email to listserv@ens.fr with no subject and one of the following commands as body: help Sends you a summary of commands subscribe csmp-digest Your Name Adds you to the mailing list signoff csmp-digest Removes you from the list Once you have subscribed, you will automatically receive each new issue as it is created. The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest. Questions related to the ftp site should be directed to scott.silver@dartmouth.edu. Currently no previous volumes of the CSMP digest are available there. Also, the digests are available to WAIS users. To search back issues with WAIS, use comp.sys.mac.programmer.src. With Mosaic, use http://www.wais.com/wais-dbs/comp.sys.mac.programmer.html. ------------------------------------------------------- >From ikb_macd@ECE.Concordia.CA (Keith MacDonald) Subject: CODE resources 101 Date: Fri, 15 Jul 1994 05:30:50 GMT Organization: ECE - Concordia University I'd like to be able to distribute files (aka plug-ins) to add features to a program I'm working on. These files would (I assume) contain code resources. I've not been able to find any examples or clear description of what I need to do to achieve this. I'm using Pascal, but I imagine C works in a similar manner. Also related to code resources - would it be possible to have a C PPC native code resource used by a non-native (written in Think Pascal) application? Thanks, Keith .............................................................................. Keith MacDonald A bridge is not a high place ikb_macd@ece.concordia.ca The fifty-second floor Computer Engineering Icarus would know Concordia University A mountain isn't far to fall Montreal, QC, CANADA When you've fallen from the moon - Marillion +++++++++++++++++++++++++++ >From mathews@ns9000.furman.edu (Owen Mathews) Date: 15 Jul 1994 17:03:44 GMT Organization: furman university computing center Keith MacDonald (ikb_macd@ECE.Concordia.CA) wrote: : I'd like to be able to distribute files (aka plug-ins) to add features : to a program I'm working on. These files would (I assume) contain code : resources. I've not been able to find any examples or clear description : of what I need to do to achieve this. I'm using Pascal, but I imagine : C works in a similar manner. : Also related to code resources - : would it be possible to have a C PPC native code resource used by : a non-native (written in Think Pascal) application? Using code resources to add functionality to an existing program doesn't require too much modification. You can "call" a code resource just like calling a function (see code example below). The main concept to under- stand is that code resources can be compiled from souce files just as an application can be. The compiler should let you do this when you are setting all of the options for compiling and linking (in SC++, the menu option is "Set Project Type"). When the resource is called, the entry point is simply the main procedure of the file. For more info, see IM. ********************this code example was taken from ********************Think Reference, copyright Symantec corp. // Calling a Code Resource // The following code illustrates how to call a // code resource. The code resource that we // are calling is given at the end // Assuming inclusion of typedef void (*MyProcPtr) (int); // Define a procedure pointer // for the code resource void DoError (OSErr err); main () { Handle myCRHandle; ProcPtr myCRPtr; int integerParam; myCRHandle = GetNamedResource ('ALCT', "\pmyBeep"); if (myCRHandle == nil) DoError (ResError()); else { HLock (myCRHandle); (* (MyProcPtr) (*myCRHandle)) (integerParam); HUnlock (myCRHandle); } } /********************************************* Here is the code resource that we're calling void main (int i) { int j; for (j = 0; j < i; j++) SysBeep (5); } **********************************************/ : Also related to code resources - : would it be possible to have a C PPC native code resource used by : a non-native (written in Think Pascal) application? PPC macs do not use the same kind of CODE resources that 68k macs do. Instead of keeping their program code in the resource fork, divided into 32K segments, PowerMacs keep code in the *data* fork of a file. It may be possible to call a PPC code chunk from a Pascal application (using the mixed-mode manager), but it will be a little different than calling a 68k code resource. -- Owen Mathews mathews@furman.edu <><><><><><><><><><><><><><><><><><><><> Furman University, Computer Science Dept +++++++++++++++++++++++++++ >From tyen@netcom.com (Anthony Yen) Date: Sat, 16 Jul 1994 09:13:13 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) In article <306fhg$fl8@ns9000.furman.edu>, Owen Mathews wrote: >PPC macs do not use the same kind of CODE resources that 68k macs do. >Instead of keeping their program code in the resource fork, divided into >32K segments, PowerMacs keep code in the *data* fork of a file. It may >be possible to call a PPC code chunk from a Pascal application (using the >mixed-mode manager), but it will be a little different than calling a >68k code resource. Hmm...several questions come to mind as I read this: Has anyone seen how to support calling PPC-native code from within a PPC-native app? And from within a fat-app? If I append some application-specific data to the data fork of a fat-app, it won't confuse the loader or whatever else Apple might have in store for the data fork in the future, right? Is there a convention for writing fat-code? That is, can I just build a CODE resource for 68K, then do what I normally do to build a fat-app but wave the magic wand over the CODE resource instead, and append the PPC code onto that resource file and wind up with a fat-loadable code module? If I can, is there a single calling convention for both loadable code modules (this refers back to my first question)? Finally, the THINK Reference code sample appears to add two dereferences over the standard function call overhead when calling a code resource. Is this correct? If it is correct, in the grand scheme of things this would not matter, but I may get down to shaving cycles in the future and if so I may need to have all code resources locked down in memory and as fully dereferenced as possible. Offhand, I see only one dereference I could avoid, by making sure the code resource is marked locked and getting a pointer out of the handle. But I'm getting a nagging feeling I'm missing something here... -- Anthony Yen Austin, Texas, USA +++++++++++++++++++++++++++ >From jwbaxter@olympus.net (John W. Baxter) Date: Sat, 16 Jul 1994 10:03:43 -0700 Organization: Internet for the Olympic Peninsula In article , tyen@netcom.com (Anthony Yen) wrote: > In article <306fhg$fl8@ns9000.furman.edu>, > Owen Mathews wrote: > >PPC macs do not use the same kind of CODE resources that 68k macs do. > >Instead of keeping their program code in the resource fork, divided into > >32K segments, PowerMacs keep code in the *data* fork of a file. It may > >be possible to call a PPC code chunk from a Pascal application (using the > >mixed-mode manager), but it will be a little different than calling a > >68k code resource. > > Hmm...several questions come to mind as I read this: > > Has anyone seen how to support calling PPC-native code from within a > PPC-native app? And from within a fat-app? Widely available for some time now. Inside Mac: PowerPC System Software various "develop" articles various "MacTech" articles > If I append some application-specific data to the data fork of a > fat-app, it won't confuse the loader or whatever else Apple might have > in store for the data fork in the future, right? fingers> The resource which tells the system where to look for the code fragment(s) provides for this. But it's probably cleaner not to put variable-length data in there, or even mutable but fixed length data. > Is there a convention for writing fat-code? That is, can I just build > a CODE resource for 68K, then do what I normally do to build a fat-app > but wave the magic wand over the CODE resource instead, and append the > PPC code onto that resource file and wind up with a fat-loadable code > module? If I can, is there a single calling convention for both > loadable code modules (this refers back to my first question)? Above references. -- John Baxter Port Ludlow, WA, USA [West shore, Puget Sound] No hablo Intel. jwbaxter@pt.olympus.net +++++++++++++++++++++++++++ >From winter@ai.rl.af.mil (Jim Wintermyre) Date: Tue, 19 Jul 1994 19:23:13 GMT Organization: Rome Laboratory In article ikb_macd@ECE.Concordia.CA (Keith MacDonald) writes: > to a program I'm working on. These files would (I assume) contain code > resources. I've not been able to find any examples or clear description > of what I need to do to achieve this. I'm using Pascal, but I imagine Check out MacTech vol. 9 no. 9 (Sept 93), "External Code Modules in Pascal." Also check out the tech note "Stand-Alone Code ad nauseum." > Also related to code resources - > would it be possible to have a C PPC native code resource used by > a non-native (written in Think Pascal) application? I believe so, but I'm not sure of the details. Check out the Mixed Mode and Code Fragment Manager chapters in New Inside Mac: Power PC System Software. Jim Wintermyre (Opinions expressed are my own, of course) winter@ai.rl.af.mil wintermyrej@lonex.rl.af.mil --------------------------- >From amundson@phenom.physics.wisc.edu (James F. Amundson) Subject: Can I do this with the Thread Manager? Date: Sat, 16 Jul 1994 21:05:16 -0600 Organization: Division of Information Technology Can someone tell me if what I have in mind is possible? I want to use the Thread Manager to give me basic preemptive multitasking without much thought. My situation is this: I'm not writing a Mac application. I'm using Think C 7.0 to run scientific calculations. My programs are entirely ANSI C with no toolbox calls other than those from the Think C ANSI libraries. I'd like to be able to run the programs I write without taking over my mac while they run. In the past, I've hacked them to call WaitNextEvent occasionally. The problem is that it takes a fair amount of effort on my part to decide where and how often I need to call WNE. Since the nature of my work involves constantly changing the programs I'm writing, adjusting my calls to WNE every time is impractical. Can I use the Thread Manager without much effort? Are there any examples of this sort of thing? Any advice will be appreciated. Thanks, Jim Amundson +++++++++++++++++++++++++++ >From first.ascent@mindlink.bc.ca (Alex Curylo) Date: 17 Jul 1994 03:17:02 GMT Organization: MIND LINK! Communications Corp. In article amundson@phenom.physics.wisc.edu (James F. Amundson) writes: > Can I use the Thread Manager without much effort? Are there any examples > of this sort of thing? Grab develop 17, and a copy of CodeWarrior 3.5. The latest iteration of PowerPlant includes a nice selection of thread classes. They're being used in a project I'm working on right now, and the fellow using them seems to have fairly positive regard for them. And for the rest of PowerPlant, as soon as they finish it ;) +++++++++++++++++++++++++++ >From rmah@panix.com (Robert Mah) Date: Sun, 17 Jul 1994 00:53:05 -0500 Organization: One Step Beyond amundson@phenom.physics.wisc.edu (James F. Amundson) wrote: ) I'm using Think C 7.0 to run scientific calculations. My programs are ) entirely ANSI C with no toolbox calls other than those from the Think ) C ANSI libraries. I'd like to be able to run the programs I write ) without taking over my mac while they run. In the past, I've hacked ) them to call WaitNextEvent occasionally. The problem is that it takes ) ... ) Can I use the Thread Manager without much effort? Are there any examples ) of this sort of thing? Thread Manager can do pre-emptive threads, _but_ only on 68K Macs. In addition, pre-emptive threads must obey the same rules as interupt level code. I.e. no drawing, no moving memory, etc. There's examples in Develop 17 that goes over using the Thread Mgr, but since using co-operative threads won't gain you much (you'll still have to call Yield() occaisionally) you should look at your code and see if you can use pre-emptive threads. Cheers, Rob _____________________________________________________________________ Robert S. Mah : Macintosh software development : 212.947.6507 One Step Beyond : and network consulting : rmah@panix.com +++++++++++++++++++++++++++ >From gwatts@fnal.fnal.gov (Gordon Watts) Date: Mon, 18 Jul 1994 00:09:54 -0600 Organization: Fermi Lab In article , rmah@panix.com (Robert Mah) wrote: > amundson@phenom.physics.wisc.edu (James F. Amundson) wrote: > > ) I'm using Think C 7.0 to run scientific calculations. My programs are > ) entirely ANSI C with no toolbox calls other than those from the Think > ) C ANSI libraries. I'd like to be able to run the programs I write > ) without taking over my mac while they run. In the past, I've hacked > ) them to call WaitNextEvent occasionally. The problem is that it takes > ) ... > ) Can I use the Thread Manager without much effort? Are there any examples > ) of this sort of thing? > > Thread Manager can do pre-emptive threads, _but_ only on 68K Macs. In > addition, pre-emptive threads must obey the same rules as interupt level > code. I.e. no drawing, no moving memory, etc. > > There's examples in Develop 17 that goes over using the Thread Mgr, but > since using co-operative threads won't gain you much (you'll still have > to call Yield() occaisionally) you should look at your code and see if > you can use pre-emptive threads. > > Cheers, > Rob It depends upon what ANSI C library calls you make. If you make calls to printf, etc. then the short answer is ... well, no. Calls to things like sqrt, etc. are ok. Basically, any call that will cause the screen to be drawn to or memory to be moved (malloc, etc.) will break with the pre-emptive threads. There are two things you can do, if you still want to use the threads. First, you can isolate your calls to printf and the like so they are never called in a preemptive thread (a thread is preemptive or cooperative when it is created, and cannot change during its lifetime). Second, and perhaps simpler, is you can implement your calculation as a cooperative thread. Sprinkle calls to "Yield()" all over the place, but don't worry too much about the placement. Just make sure there are enough of them. Now, in your main event loop you can put something like the following (this code has not been compiled/debugged!): while (!gDone) { // gDone will be set by your calc when it is finished... current_time = TickCount () + 30; // Current time plus 1/2 a second while (current_time > TickCount ()) Yield (); // Go off and do some real calculations for a 1/2 second WaitNextEvent (...); } Excuse the formatting... You will incure dead time in the Yield call, I'm not sure how much speed you are trying to get out. The fact that you are calling WaitNextEvent means that you are willing to give up some time... This will require little modification to your current application, I suspect. One bad thing about using threads if you have to figure out what your stack usage is before you run your calculation -- threads don't have a stack that grows as need be. This might be bad if you are doing lattice calculations and allocate large arrays on the stack (do it globally at compile time or by malloc while running). You can use all calls in cooperative threads, printf, malloc, etc. etc. and they will work on the powerpc. Cheers, Gordon (high energy physics). -- Gordon Watts -- gwatts@fnal.fnal.gov +++++++++++++++++++++++++++ >From Dave Falkenburg Date: Wed, 20 Jul 1994 16:43:41 GMT Organization: Apple Computer, Inc. In article Gordon Watts, gwatts@fnal.fnal.gov writes: >while (!gDone) { // gDone will be set by your calc when it is finished... > > current_time = TickCount () + 30; // Current time plus 1/2 a second > > while (current_time > TickCount ()) > Yield (); // Go off and do some real calculations for a 1/2 second > > WaitNextEvent (...); >} GACK! Please use a dynamic value for adjusting sleep timings like this: i.e. replace the "+30" with "+gRunQuantum", a value that is computed dynamically based on the compute power of the CPU. The code above means that even if we make the MacOS 100x faster, you might limit the ability for the user to switch applications down to once every two seconds. HALF A SECOND IS ALOT OF CPU TIME TO BE EATING without yielding control to other applications. -Dave Falkenburg -Apple Computer, Inc. --------------------------- >From cconstan@epdiv1.env.gov.bc.ca (Carl B. Constantine) Subject: Dice Rolling - answers Date: Thu, 21 Jul 1994 08:12:12 -0700 Organization: Ministry of Environment, Lands & Parks Finally, after much fiddling and examining of code, I finally got my dice animation working in my game. There is a trick to it. Because many people helped me, I thought I would post what I found so that others can be helped too. First, a little background. I use 3 global GWorlds to hold (a) all six dice from a PICT resource, (b) the mask and (c) a working area. This set up is similar to how john calhoun did his games like Glypa II. As mentioned above, these are all global, so I can access them from anywhere. I also use a custom window record structure that includes a GWorld which has the contents of the window in it. This is used for really fast updates (See Mac Prog. Secrets, ch 6 for more details) Now that all the GWorlds are set up and the items are in them, I use CopyMask (speed is not important in this game) to copy the dice from the diceWorld and the mask from the maskWorld to the workWorld. (with me so far?) This is a simple call. I use it twice as I have 2 dice I want to display and "roll". I can then use CopyBits to copy the workWorld to my window's offscreen GWorld for updating purposes. No problems here. The trick comes when you want to copy the dice from the GWorld to the window. When you use GWorlds, you always use GetGWorld and SetGWorld when copying from 1 GWorld to another. However, if you use this when you want to copy to the window, CopyBits makes your Mac CRASH big time!! (I ran this in the debugger in THINK C 7.0.3 and I still couldn't get out. cmd-opt-esc didn't do much, I had to restart. I have an LCIII with 12MB RAM). So what you have to do is use GetPort and SetPort when copying to the window. This works without a hitch. I then use CopyMask as I did before to copy the dice to the workWorld and CopyBits to copy from the workWorld to the window. This is still pretty fast despite the intermediate steps. I've seen some code by Tony Myles that I got off of ftp.apple.com called CopyBits vs. CopyMask. He uses CopyBits with a maskRgn to copy to the window. This is much faster. But like I said, I don't need speed. Also, you can just plain elimate the intermate step and CopyMask directly to the window instead of the workWorld and then the window. Thanks to many people on the Net for donating code (Ken Long) and help (Aaron Giles, Ingemar R., et al.) so that I can actually get this to work. -- ======================================================================== Carl B. Constantine B.C. Environment, Lands & Parks End-User Support Analyst CCONSTAN@epdiv1.env.gov.bc.ca PGP Key available if you finger: CCONSTAN@EUSACBC.env.gov.bc.ca +++++++++++++++++++++++++++ >From s828963@kub.nl (Peter Berck) Date: 22 Jul 1994 12:21:53 GMT Organization: KUB, The Netherlands In article , cconstan@epdiv1.env.gov.bc.ca (Carl B. Constantine) writes: |> Finally, after much fiddling and examining of code, I finally got my dice |> animation working in my game. There is a trick to it. |> |> Because many people helped me, I thought I would post what I found so that |> others can be helped too. |> [snip] |> |> The trick comes when you want to copy the dice from the GWorld to the |> window. When you use GWorlds, you always use GetGWorld and SetGWorld when |> copying from 1 GWorld to another. However, if you use this when you want |> to copy to the window, CopyBits makes your Mac CRASH big time!! (I ran |> this in the debugger in THINK C 7.0.3 and I still couldn't get out. |> cmd-opt-esc didn't do much, I had to restart. I have an LCIII with 12MB |> RAM). So what you have to do is use GetPort and SetPort when copying to |> the window. This works without a hitch. Uhm? Are you sure? I am writing a program which also has an offscreen GWorld which is copied to the screen (using CopyBits) when necessary. I use SetGWorld and GetGWorld all the time. In fact, NIM:Imaging with QuickDraw mentions somewhere (don't have it on me, so I can't give you the page number) that you should use SetGWorld/GetGWorld instead of GetPort and SetPort. Now I'm slightly confused. I have just started to use GWorld stuff, and I was pretty sure that Get/SetGWorld was all I needed, so if any macguru can enlighten me I'd be very grateful... -Peter - ---------------------------------------------------------------- P.J.Berck@kub.nl pgp-pubkey on request (format t "~&~{~<~%~1:;~a~>~^,~}.~%" '(DoD#-337 The-Ex Sonic-Youth NIN Dante-Alighieri Guinness)) +++++++++++++++++++++++++++ >From cconstan@epdiv1.env.gov.bc.ca (Carl B. Constantine) Date: Fri, 22 Jul 1994 11:30:50 -0700 Organization: Ministry of Environment, Lands & Parks In article <30odl1$7ro@kubds1.kub.nl>, P.J.Berck@kub.nl wrote: > In article , cconstan@epdiv1.env.gov.bc.ca (Carl B. Constantine) writes: > |> Finally, after much fiddling and examining of code, I finally got my dice > |> animation working in my game. There is a trick to it. > |> > |> Because many people helped me, I thought I would post what I found so that > |> others can be helped too. > |> > [snip] > |> > |> The trick comes when you want to copy the dice from the GWorld to the > |> window. When you use GWorlds, you always use GetGWorld and SetGWorld when > |> copying from 1 GWorld to another. However, if you use this when you want > |> to copy to the window, CopyBits makes your Mac CRASH big time!! (I ran > |> this in the debugger in THINK C 7.0.3 and I still couldn't get out. > |> cmd-opt-esc didn't do much, I had to restart. I have an LCIII with 12MB > |> RAM). So what you have to do is use GetPort and SetPort when copying to > |> the window. This works without a hitch. > > Uhm? Are you sure? I am writing a program which also has an offscreen > GWorld which is copied to the screen (using CopyBits) when necessary. > I use SetGWorld and GetGWorld all the time. In fact, NIM:Imaging with > QuickDraw mentions somewhere (don't have it on me, so I can't give you > the page number) that you should use SetGWorld/GetGWorld instead of > GetPort and SetPort. > > Now I'm slightly confused. I have just started to use GWorld stuff, > and I was pretty sure that Get/SetGWorld was all I needed, so if any > macguru can enlighten me I'd be very grateful... > It crashed my mac considerably. However, I'm piggybacking a GWorldPtr onto a custom windowRecord structure. this may be why it's crashing. I'm not sure, I haven't tested it otherwise (I don't have NIM: Imaging). I'd have to test. I have it off hand from a good source (Aaron Giles, writer of JPEGView) that you SHOULD always used GetGWorld & SetGWorld. I'm not sure why it was crashing in my system, but it was so I left it with GetPort & SetPort. Hope this helps. -- ======================================================================== Carl B. Constantine B.C. Environment, Lands & Parks End-User Support Analyst CCONSTAN@epdiv1.env.gov.bc.ca PGP Key available if you finger: CCONSTAN@EUSACBC.env.gov.bc.ca +++++++++++++++++++++++++++ >From kenlong@netcom.com (Ken Long) Date: Sat, 23 Jul 1994 14:24:16 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) Here are some fragments/snippets from Mark Hanrek, on the subjuct, ala NuCube (some names changed for another program): - ----------- WindowPtr starsWindow; // Windows and GWorlds are the same thing, so GWorldPtr gOffscreenGWorld; // use only Get/SetGWorld calls in // this app.screen" area in the window Rect gOffscreenRect; // The offscreen rect's upper-left is 0,0 Rect gProjectionRect; // The projection Rect //*******************************************************************// // Create window, offscreen GWorld, and one control for starters // //*******************************************************************// void SetupWindow (void) { Rect tempRect; //------ Set up our main window, man starsWindow = GetNewWindow (rWIND, nil, (WindowPtr) -1L); SetPort (starsWindow); ShowWindow (starsWindow); SetRect (&gProjectionRect, kHorizOffset, kVertOffset, kHorizOffset+kCubeSide, kVertOffset+kCubeSide); //¥ Set up an offscreen GWorld for preparing the next cube's image. SetRect (&gOffscreenRect, 0, 0, kCubeSide, kCubeSide); gOffscreenGWorld = CreateOffscreenGWorld (&gOffscreenRect); } void RotateCubeOnce (void) { long ticksNow; GWorldPtr windowGW; GDHandle windowGD; PixMapHandle thePixMap; GetGWorld (&windowGW, &windowGD); // Save whatever we had before SetGWorld (gOffscreenGWorld, nil); if (LockPixels (thePixMap = GetGWorldPixMap (gOffscreenGWorld))) { EraseRect (&gOffscreenGWorld->portRect); //====================================================== (action) //====================================================== // // Always set the current port to a window's port before // drawing from // a GWorld, so that the Window Manager can "clip" the // image properly // should there be other windows in front. Comment out // the next statement // and notice what happens when you drag another window in front of // the NuCube window. :) // SetGWorld (windowGW, windowGD); // Focus on a real window CopyBits ((BitMapPtr)*thePixMap, (BitMapPtr)&starsWindow->portBits, &gOffscreenRect, &gProjectionRect, srcCopy, nil); UnlockPixels (thePixMap); } SetGWorld (windowGW, windowGD); // Okay if this is redundant } //*******************************************************************// // Use the following function for the rest of your programming // days. // Do not alter it in any way. It is a complete functional unit // doing all REQUIRED things. //*******************************************************************// GWorldPtr CreateOffscreenGWorld (Rect *theRect) { CGrafPtr currentPort; GDHandle currentGDevice; GWorldPtr offScreen; QDErr result; GetGWorld (¤tPort, ¤tGDevice); //-- If there is not enough application memory, try MultiFinder //-- temporary memory. if ((result = NewGWorld (&offScreen, 0, theRect, nil, nil, 0L)) != noErr) if ((result = NewGWorld (&offScreen, 0, theRect, nil, nil, useTempMem)) != noErr) return (nil); SetGWorld (offScreen, nil); //-- Initialize the clipping "hole" to be the same as the //-- drawing area. ClipRect (&offScreen->portRect); //-- The GWorld has random stuff in it, so we'll erase it to //-- white. if (LockPixels (GetGWorldPixMap (offScreen))) { ForeColor (blackColor); BackColor (whiteColor); EraseRect (&offScreen->portRect); UnlockPixels (GetGWorldPixMap (offScreen)); } SetGWorld (currentPort, currentGDevice); return offScreen; } //*******************************************************************// // Shut down with charm, grace and decorum. //*******************************************************************// void MoveAlongHome (void) { DisposeWindow (starsWindow); // Not "CloseWindow" DisposeGWorld (gOffscreenGWorld); } - -------------- That's all, folks. -Ken- --------------------------- >From rkwee@ee.pdx.edu (Roland Kwee) Subject: Easy file access functions [source] Date: 18 Jul 1994 20:35:28 -0700 Organization: (none) Some days ago I promised to upload some source code that makes handling Mac file functions as easy as the standard ANSI C library functions. Hopefully I didn't leave out code that is essential to understand and use my little system. Here is my Macintosh ThinkC source code for accessing files pretty much like with the ANSI C library functions. Hopefully the code is sufficiently commented to be understandible. Note that there is a test function that demonstrates how to use the other functions. Please let me know if this is useful, understandable, and if you see problems or improvements. --Roland Kwee email: RolandKwee@ACM.org /*---------------------------------------------------------------------------------- * globals.h Roland Kwee May 25, 1994 * This file contains the declarations for the application-specific global data. * * A good strategy may be to declare a number of global variables in a single * structure. With the menu options, the user can change one or more of these * global settings. These settings are global to allow easy access by the * functions that actually perform tasks. By keeping them in a single * structure, they are easy to keep track of. *---------------------------------------------------------------------------------- */ #ifndef __GLOBALS_H__ #define __GLOBALS_H__ enum Creators{CREATOR='TrRK'}; enum FileTypes{UNKNOWN, PostScript, Binary, TextDos, TextUnix, TextMac, Hathaway, Rochester, RochesterHeader, BEN5000, PPSM, Support, Spreadsheet}; /* This structure communicates user input to the process. */ struct Option_s{ int Quit; int SeparateDigCh, OutputType, LPFcorrection, DiagnosticWindow, ProgressDialog, Fast; int debug, test_partly; /* default: 0 (no debug output). */ void *OpenFileList, *PrintFileList; float TimeZoneHourOffset; char DefaultLocation[5]; }; extern struct Option_s Option; #endif /* __GLOBALS_H__ */ /* MacFile.h Roland Kwee June 1, 1994 * Functions to make handling files on the Mac almost as easy as in Unix. * This will make it possible to port programs between Unix and the Mac. */ #ifndef _MACUTIL_H__ #define _MACUTIL_H__ #include #include #include #include //============== // Project Info: //============== // compiler: Symantec C++ for Macintosh, 1994, ThinkC (version 7 ?) // libraries: MacTraps, SANE, ANSI // Executable: // file name: Translate // File Type: APPL, Creator: TrRK // Compiler settings: // int: 2 bytes // float: 4 bytes // double: 8 bytes // don't use the "native" floating point format #if __option(native_fp) #error Don't use the "native" floating point format (Edit/Options/Compiler settings). #endif // printf can only handle float and doubles if double is not set to 8 bytes: #if __option(double_8) #error Don't set doubles to 8 bytes (Edit/Options/Compiler settings). #endif // REASONS FOR FLOATING POINT SETTINGS: // The input file has IEEE double numbers, but the input routine is able to convert these // to Mac format using the Mac type `short double' which is equal to IEEE double. // The library function printf is compiled with the standard settings, so the formats for // floating point will work incorrectly if the program is compiled with the `8-byte doubles' option. // Better not to recompile the library, so set all floating point options to Mac standard. /* ===============definitions for byte order ===================== */ enum {BigEndian /* Motorola, VAX */, LittleEndian /* Intel */}; //extern int computerbyteorder; #define computerbyteorder BigEndian /*=========================== TIME ZONE ============================*/ /* This should be a menu option. For now it is constant. * Valid values are -12.0 .. 12.0. Positive is East of Greenwich. * Simple fractions like 9.5 (Adelaide, Australia) should work. */ #define TZ -7 /* This global can be used with sprintf to prepare a string to pass to Log(). */ extern char buf[1000]; void Log(char *msg); void SystemError(char *msg, char *source, int code); void Warn(char *msg); char *PtoCstrPtr(void *Pstring); void LtoCstr(OSType l, char *s); char *FSStoCstrPtr(FSSpec *file); char *GetBaseName(FSSpec *file); char *GetFullPathName(FSSpec *file); void GetFullPath(int VolumeSpec, long ParentDirID, char *fullPath); int FSSpecRoutinesAvail(void); FSSpec *select_input_file(const int numTypes, SFTypeList myTypes); FSSpec *select_output_file(const char *prompt, const char *defname); void FinderInfo(FSSpec *fs); void PathInfo(FSSpec *fs); char *GetVolumeName(FSSpec *fs); void VolumeInfo(FSSpec *fs); void TestPathUtils(void); #if 0 /* See Mac include file */ struct FSSpec { short vRefNum; long parID; Str63 name; }; typedef struct FSSpec FSSpec; typedef FSSpec *FSSpecPtr, **FSSpecHandle; typedef FSSpecPtr FSSpecArrayPtr; /* pointer to array of FSSpecs */ #endif typedef struct{ int in_use; /* To maintain the file table. */ FSSpec fss; /* Specification of the (closed) file selected with a dialog. */ short refnum; /* Reference number, or access path of the open file. */ int byteorder; }MacFILE; /* This structure is currently only used to hold the year of a file. * It doesn't really matter whether last access or last modify. */ struct MacStat{ long st_size; /* total size of file, in bytes */ int year; #if 0 time_t st_atime; /* file last access time */ time_t st_mtime; /* file last modify time */ time_t st_ctime; /* file last status change time */ #endif }; #define File MacFILE #define FileRead macfread #define FWRITE macfwrite #define FSEEK macfseek #define FSTAT macfstat #define STAT_T struct MacStat MacFILE *macftype(FSSpec *selection, long creator, long type); MacFILE *macfopen(FSSpec *selection, char *mode); int macfclose(MacFILE *fp); int macfread(void *buf, size_t recsize, size_t recnum, MacFILE *fp); int macfwrite(void *buf, size_t recsize, size_t recnum, MacFILE *fp); int macfseek(MacFILE *fp, long offset, int whence); long macftell(MacFILE *fp); int macfstat(MacFILE *fp, struct MacStat *buf); void copy_file(MacFILE *fp_in, MacFILE *fp_out); int TestFileType(MacFILE *fp); void TestFileUtils(void); void BetterMoveWindow(WindowPtr wp, float right, float down); void SwapN(void *buf, int n); int NeedSwap(MacFILE *fp, void *buf, int n); char GetInputByte(File *fp); // Reads and returns one byte. int GetInputInt(File *fp); // Reads, converts and returns one integer. long GetInputLong(File *fp); unsigned long GetInputULong(File *fp); float GetInputFloat(File *fp); double GetInputDouble(File *fp); /* reads IEEE 8-byte double, returns Mac double. */ /* GetInputString - Reads a string and returns a null-terminated C-string. Reading stops when a '\0' char, or `size' characters have been read. A '\0' is added. If you are certain that the string to read is terminated with a '\0', then `size' can be the size of the buffer. Otherwise, the buffer needs to be one character bigger, to hold the added '\0'. */ char *GetInputString(char *buf, int size, File *fp); /* GetInputNString - Reads n characters and returns a string in str. str needs to have room for an additional '\0'. */ char *GetInputNString(char *str, int n, File *fp); /* SwapN - swaps n bytes of buf in place */ void SwapN(void *buf, int n); // Writes a C string to the output file. int WriteTxt(File *fp, char *str); // Writes bytes to a binary output file. int WriteBin(File *fp, void *buf, int size); // Specialized functions to write data, argument may be a constant void WriteULong(File *fp, unsigned long x); void WriteLong(File *fp, long x); void WriteShort(File *fp, signed short x); #endif /* _MACUTIL_H__ */ /* MacFile.c Roland Kwee June 1, 1994 * Functions to make handling files on the Mac almost as easy as in Unix. * This will make it possible to port programs between Unix and the Mac. */ #include "MacFile.h" #include "globals.h" #include #include /* cshow() */ /* This global can be used with sprintf to prepare a string to pass to Log(). */ char buf[1000]; /*---------------------------------------------------------------------------------- * Log() - Diagnostic output. Adds a newline at the end. *----------------------------------------------------------------------------------*/ void Log(char *msg){ if(Option.debug) puts(msg); return; } /*---------------------------------------------------------------------------------- * SystemError() - Error output. Should be a alert box. *----------------------------------------------------------------------------------*/ void SystemError(char *msg, char *source, int code){ /* Force visible output. */ if(!Option.debug){ Option.debug=1; cshow(stdout); } sprintf(buf, "Error: %s%s%s code: %d", msg, source?" in function: ":"", source?source:"", code); Log(buf); return; } /*---------------------------------------------------------------------------------- * Warn() - Warning output. * * Should be a modal dialog box IF the diagnostic window is closed. * Or, there should be an option to suppress the modal dialog box to * allow unattended transfer of large batches of files. * *----------------------------------------------------------------------------------*/ void Warn(char *msg){ Log(msg); return; } /*---------------------------------------------------------------------------------- * PtoCstrPtr() - Converts a Pascal string to a pointer to a C String. * The string the pointer points to is reused for each new call. *----------------------------------------------------------------------------------*/ char *PtoCstrPtr(void *Pstring){ static char Cstring[257]; char *str; int i, max; str=Pstring; max=str[0]; memcpy(Cstring, str+1, max); Cstring[max]='\0'; return Cstring; } /*---------------------------------------------------------------------------------- * LtoCstr() - Converts an OSType (long) to a C-string (char[5]). *----------------------------------------------------------------------------------*/ void LtoCstr(OSType l, char *s){ //sprintf(buf, "LtoCstr: 0x%08X", l); Log(buf); memcpy(s, (char*)&l, 4); s[4]='\0'; return; } /*---------------------------------------------------------------------------------- * FSStoCstrPtr() - Converts a FSS file specification to a C string. * The string the pointer points to is reused for each new call. * See: New Inside Mac, "Files", p. 2-45: Constructing Full Pathnames, Listing 2-5. *----------------------------------------------------------------------------------*/ char *FSStoCstrPtr(FSSpec *file){ static char fullPath[300]; CInfoPBRec myPB; Str255 dirName; OSErr myErr; strcpy(fullPath, PtoCstrPtr(file->name));/* Start with base file name. */ myPB.dirInfo.ioNamePtr=dirName; /* Output buffer for PBGetCatInfo(). */ myPB.dirInfo.ioVRefNum=file->vRefNum; /* Volume ID */ myPB.dirInfo.ioDrParID=file->parID; /* Initialize parent dir. */ myPB.dirInfo.ioFDirIndex= -1; /* <0: Use ioDrDirID as input. */ myPB.dirInfo.ioCompletion=NULL; for( myPB.dirInfo.ioDrDirID=file->parID; myPB.dirInfo.ioDrDirID!=fsRtDirID; myPB.dirInfo.ioDrDirID=myPB.dirInfo.ioDrParID){ myErr=PBGetCatInfo(&myPB, FALSE); if(myPB.dirInfo.ioResult==noErr){ strcat(fullPath, ":"); strcat(fullPath, PtoCstrPtr(dirName)); }else break; } return fullPath; } /*---------------------------------------------------------------------------------- * GetBaseName() - Converts a FSS file specification to a C string containing * the base file name, i.e., without the path. * The string the pointer points to is reused for each new call. *----------------------------------------------------------------------------------*/ char *GetBaseName(FSSpec *file){ static char fullPath[100]; /* Semi-permanent, reused. */ strcpy(fullPath, PtoCstrPtr(file->name)); /* Add file name. */ return fullPath; /* Return pointer. */ } /*---------------------------------------------------------------------------------- * GetFullPathName() - Converts a FSS file specification to a C string containing * the full path and the file name. * The string the pointer points to is reused for each new call. * See: New Inside Mac, "Files", p. 2-45: Constructing Full Pathnames, Listing 2-5. *----------------------------------------------------------------------------------*/ char *GetFullPathName(FSSpec *file){ static char fullPath[1000]; /* Semi-permanent, reused. */ strcpy(fullPath, GetVolumeName(file)); /* Start with disk name. */ strcat(fullPath, ":"); /* Path always ends with colon. */ GetFullPath(file->vRefNum, file->parID, fullPath); /* Find full path. */ strcat(fullPath, PtoCstrPtr(file->name)); /* Add file name. */ return fullPath; /* Return pointer. */ } /*---------------------------------------------------------------------------------- * GetFullPath() - Returns full path name (without file name) in fullPath. Recursive. * * See: New Inside Mac, "Files", p. 2-45: Constructing Full Pathnames, Listing 2-5. * Because strcat() cannot handle overlapping strings, recursion is easier than * an iteration. The parts of the path are pasted together AFTER all parts are found. *---------------------------------------------------------------------------------- */ void GetFullPath(int VolumeSpec, long ParentDirID, char *fullPath){ Str255 dirName; CInfoPBRec myPB; OSErr myErr; myPB.dirInfo.ioVRefNum=VolumeSpec; myPB.dirInfo.ioDrDirID=ParentDirID; myPB.dirInfo.ioFDirIndex= -1; /* <0: Use ioDrDirID as input. */ myPB.dirInfo.ioCompletion=NULL; myPB.dirInfo.ioNamePtr=dirName; /* Output buffer for PBGetCatInfo(). */ myErr=PBGetCatInfo(&myPB, FALSE); /* receive parent dir in dirName */ if(myErr==noErr){ if(myPB.dirInfo.ioDrParID!=fsRtDirID) /* This is the root dir ID. */ GetFullPath(VolumeSpec, myPB.dirInfo.ioDrParID, fullPath); /* RECURSION */ strcat(fullPath, PtoCstrPtr(dirName)); /* paste parent to ancestors */ strcat(fullPath, ":"); /* Path always ends with colon. */ } return; } /*---------------------------------------------------------------------------------- * FSSpecRoutinesAvail() - Returns true if the FSS functions are available. *---------------------------------------------------------------------------------- */ int FSSpecRoutinesAvail(void){ OSErr myErr = !noErr; long myFeature; int avail=0; if(1/*gHasGestalt()*/){ myErr=Gestalt(gestaltFSAttr, &myFeature); if(myErr==noErr && (myFeature & gestaltHasFSSpecCalls)) avail=1; else Log("Gestalt error"); }else Log("Gestalt is not available"); if(avail) Log("FSS Routines Available"); return avail; } /*---------------------------------------------------------------------------------- * select_input_file() - Allows the user to select an input file with a standard dialog box. * If numTypes == -1, all file types are displayed. * Returns: pointer to FSS record, or NULL on error or cancel. * See: New Inside Mac, "Files", p. 1-19: Opening a File, Listing 1-6. *----------------------------------------------------------------------------------*/ FSSpec *select_input_file(const int numTypes, SFTypeList myTypes){ static StandardFileReply myReply; OSErr myErr=noErr; StandardGetFile(NULL, numTypes, myTypes, &myReply); if(myReply.sfGood){ char type[5]; LtoCstr(myReply.sfType, type); sprintf(buf, "select_input_file: Type: %s", type); Log(buf); return &myReply.sfFile; }else return NULL; } /*---------------------------------------------------------------------------------- * select_output_file() - Allows the user to select an output file with a standard dialog box. * Returns: pointer to FSS record, or NULL on error or cancel. *----------------------------------------------------------------------------------*/ FSSpec *select_output_file(const char *prompt, const char *defname){ Str255 Pprompt, Pdefname; static StandardFileReply myReply; OSErr myErr=noErr; strcpy((char *)Pprompt, prompt); CtoPstr((char *)Pprompt); strcpy((char *)Pdefname, defname); CtoPstr((char *)Pdefname); /* The cursor is set to an I-beam to edit the file name in the * dialog box. Reset it to the default arrow. */ StandardPutFile(Pprompt, Pdefname, &myReply); InitCursor(); if(myReply.sfGood){ return &myReply.sfFile; }else return NULL; } /*---------------------------------------------------------------------------------- * FinderInfo() - Test output of Finder Info of a file: creator, type... *----------------------------------------------------------------------------------*/ void FinderInfo(FSSpec *fs){ OSErr myErr; FInfo fndrInfo; char creator[5], type[5]; myErr=FSpGetFInfo(fs, &fndrInfo); LtoCstr(fndrInfo.fdType, type); LtoCstr(fndrInfo.fdCreator, creator); Log("-------------------------"); strcpy(buf, "Getting Finder Info: "); switch(myErr){ case noErr: strcat(buf, "No error"); break; case nsvErr: strcat(buf, "No such volume"); break; case ioErr: strcat(buf, "I/O error"); break; case bdNamErr: strcat(buf, "Bad filename"); break; case fnfErr: strcat(buf, "File not found"); break; case paramErr: strcat(buf, "No default volume"); break; case dirNFErr: strcat(buf, "Directory not found or incomplete pathname"); break; case afpAccessDenied: strcat(buf, "User does not have the correct access"); break; case afpObjectTypeErr: strcat(buf, "Directory not found or incomplete pathname"); break; default : strcat(buf, "Unknown error"); break; } Log(buf); if(myErr==noErr){ sprintf(buf, "Type: '%s' Creator: '%s', Flags: 0x%04X, Location: X=%d Y=%d, Directory: %d", type, creator, fndrInfo.fdFlags, fndrInfo.fdLocation.h, fndrInfo.fdLocation.v, fndrInfo.fdFldr); Log(buf); } return; } /*---------------------------------------------------------------------------------- * PathInfo() - Test output with info on the PathID. *----------------------------------------------------------------------------------*/ void PathInfo(FSSpec *fs){ CInfoPBRec myPB; Str255 dirName; OSErr myErr; myPB.dirInfo.ioNamePtr=dirName; /* Output buffer for PBGetCatInfo(). */ myPB.dirInfo.ioVRefNum=fs->vRefNum; /* Volume ID */ myPB.dirInfo.ioDrDirID=fs->parID; myPB.dirInfo.ioFDirIndex= -1; /* <0: Use ioDrDirID as input. */ Log("-------------------------"); myErr=PBGetCatInfo(&myPB, FALSE); sprintf(buf, "Getting Path Info: %s", myErr==noErr?"OK":"Error"); Log(buf); sprintf(buf, "ID of this dir: %ld, Parent dir: \"%s\"", myPB.dirInfo.ioDrDirID, PtoCstr(dirName)); Log(buf); sprintf(buf, "ID of parent dir: %ld, Files in dir: %d", myPB.dirInfo.ioDrParID, myPB.dirInfo.ioDrNmFls); Log(buf); return; } /*---------------------------------------------------------------------------------- * GetVolumeName() - Returns pointer to the volume name specified in fs. *----------------------------------------------------------------------------------*/ char *GetVolumeName(FSSpec *fs){ static char name[35]; /* Volume names are up to 27 chars. */ HParamBlockRec myHPB; OSErr myErr; myHPB.volumeParam.ioNamePtr=(StringPtr)name; myHPB.volumeParam.ioVRefNum=fs->vRefNum; myHPB.volumeParam.ioVolIndex=0; myErr=PBHGetVInfo(&myHPB, FALSE); PtoCstr((StringPtr)name); return name; } /*---------------------------------------------------------------------------------- * VolumeInfo() - Test output. *----------------------------------------------------------------------------------*/ void VolumeInfo(FSSpec *fs){ HParamBlockRec myHPB; OSErr myErr; char name[35]; /* Volume names are up to 27 chars. */ long bytes, MB=1024L*1024L; myHPB.volumeParam.ioNamePtr=(StringPtr)name; myHPB.volumeParam.ioVRefNum=fs->vRefNum; myHPB.volumeParam.ioVolIndex=0; myErr=PBHGetVInfo(&myHPB, FALSE); Log("-------------------------"); sprintf(buf, "Getting Volume Info: %s", myErr==noErr?"OK":"Error"); Log(buf); sprintf(buf, "Drive Number: %d, Volume Specification Number: %d", myHPB.volumeParam.ioVDrvInfo, myHPB.volumeParam.ioVRefNum); Log(buf); sprintf(buf, "Allocation Block Size: %ld bytes", myHPB.volumeParam.ioVAlBlkSiz); Log(buf); sprintf(buf, "Clump Size: %ld bytes", myHPB.volumeParam.ioVClpSiz); Log(buf); sprintf(buf, "Free: %d Allocation Blocks", myHPB.volumeParam.ioVFrBlk); Log(buf); bytes=myHPB.volumeParam.ioVFrBlk * myHPB.volumeParam.ioVAlBlkSiz; sprintf(buf, "Name: %s, Free: %ld bytes = %g MB", PtoCstrPtr(myHPB.volumeParam.ioNamePtr), bytes, (float)bytes/MB); Log(buf); return; } /*---------------------------------------------------------------------------------- * TestPathUtils() *----------------------------------------------------------------------------------*/ void TestPathUtils(void){ FSSpecRoutinesAvail(); /* Test of PtoCstrPtr(). */ { char *str; Str255 Pstr="\pHello"; str=PtoCstrPtr(Pstr); Log(str); } /* Test of select_input_file(). */ { SFTypeList myTypes; FSSpec *fs; //myTypes[0]='TEXT'; fs=select_input_file(-1, myTypes); if(fs==NULL){ Log("Error select_input_file() or user cancelled"); return; } FinderInfo(fs); VolumeInfo(fs); PathInfo(fs); if(fs){ Log("-------------------------"); Log("Getting full name"); { char *fullname=FSStoCstrPtr(fs); sprintf(buf, "FSStoCstrPtr: %s", fullname);Log(buf); fullname=GetFullPathName(fs); sprintf(buf, "GetFullPathName: %s", fullname);Log(buf); } Log("-------------------------"); } } return; } /*---------------------------------------------------------------------------------- * macftype() - Changes the file type and creator if specified. * Example: macftype(fss, 0L, 'TEXT'); *----------------------------------------------------------------------------------*/ MacFILE *macftype(FSSpec *selection, long creator, long type){ short vRefNum=selection->vRefNum; long dirID =selection->parID; Str255 fileName; FInfo fndrInfo; /* FSSpec.name is 63 byte string */ memcpy(fileName, selection->name, sizeof(selection->name)); HGetFInfo(vRefNum, dirID, fileName, &fndrInfo); if(creator) fndrInfo.fdCreator=creator; if(type) fndrInfo.fdType =type; HSetFInfo(vRefNum, dirID, fileName, &fndrInfo); return; } /*---------------------------------------------------------------------------------- * macfopen() - Returns a pointer to an entry in the file table, or NULL on error. *----------------------------------------------------------------------------------*/ MacFILE *macfopen(FSSpec *selection, char *mode){ /* This is the file table. */ static MacFILE mac_file_table[FOPEN_MAX]; /* Like ANSI C */ int i; OSErr myErr; SignedByte permissions; if(selection==NULL) return; /* Find a free slot. */ for(i=0; ivRefNum; myHPB.volumeParam.ioVolIndex=0; myErr=PBHGetVInfo(&myHPB, FALSE); /* Check if the volume is locked. FSpOpenDF() will still open the * file for write access, but writing will cause an error. * See New Inside Mac, "Files", p. 2-8. * It recommends calling PGHGetVInfo(), which is described at p. 2-144. * HOWEVER, I can't find the description for the * volume attributes ioVAtrb ??? */ //if(myHPB.volumeParam.ioVAtrb & ????????) // return NULL; permissions=fsRdWrPerm; }else permissions=fsRdPerm; /* Open it. If file-to-write not found, create it and try again. */ myErr=FSpOpenDF(selection, permissions, &mac_file_table[i].refnum); if(myErr==fnfErr && permissions==fsRdWrPerm) if(noErr==FSpCreate(selection, CREATOR, 'TEXT', smSystemScript)) myErr=FSpOpenDF(selection, permissions, &mac_file_table[i].refnum); if(myErr!=noErr) return NULL; mac_file_table[i].in_use=1; mac_file_table[i].byteorder=BigEndian; /* Assume it is a Mac type file. */ memcpy(&mac_file_table[i].fss, selection, sizeof(FSSpec)); return &mac_file_table[i]; } /*---------------------------------------------------------------------------------- * macfclose() - Closes the file and flushes the volume, or returns non-zero on error. *----------------------------------------------------------------------------------*/ int macfclose(MacFILE *fp){ OSErr myErr; if(fp==NULL) return; myErr=FSClose(fp->refnum); if(myErr==noErr){ FlushVol(NULL, fp->fss.vRefNum); return 0; }else return EOF; } /*---------------------------------------------------------------------------------- * macfread() - Like fread(). *----------------------------------------------------------------------------------*/ int macfread(void *buf, size_t recsize, size_t recnum, MacFILE *fp){ OSErr myErr=noErr; long count=recsize; int rec; char *Buffer=buf; if(fp==NULL) return; /* Transfer data in the chunks as specified. */ for(rec=0; recrefnum, &count, Buffer); Buffer += count; } /* Count only records that transferred successfully. */ if(myErr!=noErr) rec--; /* Return how many records transferred successfully. */ return rec; } /*---------------------------------------------------------------------------------- * macfwrite() - Like fwrite(). *----------------------------------------------------------------------------------*/ int macfwrite(void *buf, size_t recsize, size_t recnum, MacFILE *fp){ OSErr myErr=noErr; long count=recsize; int rec; char *Buffer=buf; if(fp==NULL) return; /* Transfer data in the chunks as specified. */ for(rec=0; recrefnum, &count, Buffer); Buffer += count; } /* Count only records that transferred successfully. */ if(myErr!=noErr) rec--; /* Return how many records transferred successfully. */ return rec; } /*---------------------------------------------------------------------------------- * TestFileType() - Determines what kind the open file is. *----------------------------------------------------------------------------------*/ int TestFileType(MacFILE *fp){ char buf[100]; int i, ctrl=0, bin=0, ret=0, nl=0, esc=0, Rochester=0, Hathaway=0, ps=0; if(fp==NULL) return; if(1==macfread(buf, sizeof(buf), 1, fp)){ /* Test for headers. */ if(!strncmp(buf, "%!", 2)) ps++; if(!strncmp(buf, "DSM version ", 12)) Hathaway++; /* Does the Rochester file have a header? */ /* Test the bytes. */ for(i=0; i0x7f) bin++; break; } } } sprintf(buf, "ctrl=%d, bin=%d, ret=%d, nl=%d, esc=%d", ctrl, bin, ret, nl, esc); Log(buf); if(Rochester) Log("Rochester Transient Fault Recorder file"); if(Hathaway) Log("Hathaway Digital Signal Monitor file"); if(ps) Log("PostScript file"); if(bin) Log("Binary file"); else{ if(!ret && nl) Log("Unix text file"); if( ret && !nl) Log("Macintosh text file"); if( ret && nl) Log("MS-DOS text file"); } return 0; } /*---------------------------------------------------------------------------------- * macfseek() - Like fseek(). *----------------------------------------------------------------------------------*/ int macfseek(MacFILE *fp, long offset, int whence){ OSErr myErr; short posMode; if(!fp) return -1; switch(whence){ case SEEK_SET: posMode=fsFromStart; break; case SEEK_CUR: posMode=fsFromMark; break; case SEEK_END: posMode=fsFromLEOF; break; default: return -1; break; } myErr=SetFPos(fp->refnum, posMode, offset); return myErr==noErr?0:-1; } /*---------------------------------------------------------------------------------- * macftell() - Like ftell(). *----------------------------------------------------------------------------------*/ long macftell(MacFILE *fp){ OSErr myErr; long offset; if(!fp) return -1; myErr=GetFPos(fp->refnum, &offset); if(myErr!=noErr) errno=1; /* Required by ANSI C standard. */ return myErr==noErr?offset:-1L; } /*---------------------------------------------------------------------------------- * macfstat() - Get file status. Returns zero on success, or -1 on error. * Not all unix features are implemented yet. *----------------------------------------------------------------------------------*/ int macfstat(MacFILE *fp, struct MacStat *buf){ static char name[35]; /* Volume names are up to 27 chars. */ HParamBlockRec myHPB; /* New Ins.Mac, `Files', p. 2-269 */ OSErr myErr; DateTimeRec date; if(!buf) return -1; myHPB.volumeParam.ioCompletion=0; myHPB.volumeParam.ioNamePtr=(StringPtr)fp->fss.name; myHPB.volumeParam.ioVRefNum=fp->fss.vRefNum; myHPB.fileParam.ioFDirIndex=0; myHPB.fileParam.ioDirID=fp->fss.parID; myErr=PBHGetFInfo(&myHPB, FALSE); /* New Ins.Mac, `Files', p. 2-194 */ Secs2Date(myHPB.fileParam.ioFlMdDat, &date); buf->year=date.year; return myErr==noErr?0:-1; } /*---------------------------------------------------------------------------------- * copy_file() - For testing. *----------------------------------------------------------------------------------*/ void copy_file(MacFILE *fp_in, MacFILE *fp_out){ #define recsiz 100 char rec[recsiz]; int irec, nrec, lrec; long fsiz; if(!fp_in || !fp_out) return; /* File size. */ macfseek(fp_in, 0L, SEEK_END); fsiz=macftell(fp_in); nrec=fsiz/recsiz; lrec=fsiz-(nrec*recsiz); /* Size of last, partial, record. */ macfseek(fp_in, 0L, SEEK_SET); macfseek(fp_out, 0L, SEEK_SET); sprintf(buf, "File size: %ld bytes = %d chunks of %d bytes plus one of %d bytes", fsiz, nrec, recsiz, lrec); Log(buf); /* Transfer full records. */ for(irec=0; irecportRect; h=r.bottom-r.top; /* height */ w=r.right-r.left; /* width */ x=(screenBits.bounds.right-w) * right; if(x<10) x=10; y=(screenBits.bounds.bottom-30-h) * down +30; /* Menubar is 30 pixels high. */ if(y<30) y=30; MoveWindow(wp, x, y, TRUE); } /*---------------------------------------------------------------------------------- * SwapN() - swaps n bytes of buf in place, also convert IEEE 8-byte double to * Macintosh double (12-byte) *----------------------------------------------------------------------------------*/ void SwapN(void *buf, int n){ char c, *b, *e; for(b=buf, e=b+n-1; bbyteorder){ SwapN(buf, n); return 1; }else return 0; } /*==================== INPUT FUNCTIONS =================*/ char GetInputByte(File *fp){ char buf; long size=sizeof(buf); FileRead(&buf, size, 1, fp); return buf; } int GetInputInt(File *fp){ int buf; long size=sizeof(buf); FileRead((char *)&buf, size, 1, fp); NeedSwap(fp, &buf, sizeof(buf)); return buf; } long GetInputLong(File *fp){ long buf; long size=sizeof(buf); FileRead((char *)&buf, size, 1, fp); NeedSwap(fp, &buf, sizeof(buf)); return buf; } unsigned long GetInputULong(File *fp){ unsigned long buf; long size=sizeof(buf); FileRead((char *)&buf, size, 1, fp); NeedSwap(fp, &buf, sizeof(buf)); return buf; } float GetInputFloat(File *fp){ float buf; long size=sizeof(buf); FileRead((char *)&buf, size, 1, fp); NeedSwap(fp, &buf, sizeof(buf)); return buf; } /* Note: make sure to use the 8-byte IEEE-compatible short double on the Mac and not one of the Mac native 80 or 96 bit (10 or 12 byte) formats. */ double GetInputDouble(File *fp){ double retval; #ifdef THINK_C short double buf; /* IEEE-compatible 8-byte floating point on Mac. */ #else double buf; #endif long size=sizeof(buf); FileRead((char *)&buf, size, 1, fp); NeedSwap(fp, &buf, sizeof(buf)); retval=buf; /* Convert to Mac native format. */ return retval; } char *GetInputString(char *str, int len, File *fp){ int i, itemsread; char buf; long size=sizeof(buf); for(i=0; iFrom reinder@neuretp.biol.ruu.nl (Reinder Verlinde) Subject: How to detect whether Debugger is installed? Date: Mon, 11 Jul 1994 12:10:44 GMT Organization: Rijksuniversiteit Utrecht The subject says it all: How do you detect whether MacsBug is present? I want to know this since I have this FKEY which should activate MacsBug, and not do anything when MacsBug is not present. The usual TrapAvailable method does not seem to work since GetTrapAddress( _Unimplemented) == GetTrapAddress( _Debugger) irrespective of the presence of MacsBug. I also looked up the Gestalt selectors, and there is one to check whether the Debugger Utilities are present, but I can't find one to check the presence of the Debugger. I can think of numerous imperfect ways to check this (comparing first bytes of _Unimplemented with a copy in my code, checking for MacsBug in the System Folder, etcetera), but there should be a perfect way. reinder@neuretp.biol.ruu.nl (Reinder Verlinde) +++++++++++++++++++++++++++ >From busfield@hurricane.seas.ucla.edu (John D. Busfield) Date: Wed, 13 Jul 1994 16:14:40 GMT Organization: School of Engineering & Applied Science, UCLA. In <1994Jul11.121044.4311@cc.ruu.nl> reinder@neuretp.biol.ruu.nl (Reinder Verlinde) writes: >The subject says it all: How do you detect whether MacsBug is present? >I want to know this since I have this FKEY which should activate >MacsBug, >and not do anything when MacsBug is not present. Here's what it says in Macsbug Reference and Debugging Guide pg 412 How MacsBug installs itself. When a system error or 68000 exception occurs, the ROM code examines the global variable MacJmp to obtain the address of the debuggers entry point. MacJmp might contain additional information, depending on whether you are running under a 24-bit or 32-bit Memory Manager. If you are running under a 24-bit Memory Manager, the high-order byte of MacJmp is a flags byte that contains the following information. Bit Meaning 7 Set if debugger is running 6 Set if debugger can handle system errors 5 Set if debugger is installed 4 Set if debugger can support the Discipline utility The lower 3 bytes of MacJmp are used to store the address of the debugger's entry point. If you are running under a 32-bit Memory Manager, the flags byte is moved to address $BFF and the long word at MacJmp becomes a full 32-bit address that points to the debugger's entry point. So to answer your question, you should only need to look at bit 5 of the flags byte. -- - ---------------------------------------------------------------------------- John Busfield | All my realities are virtual busfield@hurricane.seas.ucla.edu _____________________________________________________________________________ +++++++++++++++++++++++++++ >From dlamkins@tiac.net (David B. Lamkins) Date: 17 Jul 1994 00:48:29 GMT Organization: DBL Systems In article <1994Jul11.121044.4311@cc.ruu.nl> reinder@neuretp.biol.ruu.nl (Reinder Verlinde) writes: > The subject says it all: How do you detect whether MacsBug is present? The following Pascal unit does everything you need (except give you C code.) The Apple manual doesn't tell the entire story -- the comments in the code tell which debuggers and system patches break the rules. unit DebuggerTest; interface type DebuggerKind = ( {} debuggerKindNone, {} debuggerKindMacsBug, {} debuggerKindTMON, {} debuggerKindJasik, {} debuggerKindABZmon, {} debuggerKindOther {} ); DebuggerSignature = packed array[1..2] of Char; {$IFC (UNDEFINED DebuggerTest_Signature) | DebuggerTest_Signature} procedure GetDebuggerInfo (var present, active: Boolean; var kind: DebuggerKind; var signature: DebuggerSignature); {$ENDC} {ABZmon can load Òon top ofÓ another debugger. In this case, the underlying debugger} {becomes the secondary debugger, but is the only one reported by GetDebuggerInfo, which} {looks in the ÒnormalÓ places before trying to find ABZmon. The ABZMonIsLoaded function} {can be used to detect ABZmonÕs presence when not the only debugger.} function ABZMonIsLoaded: Boolean; function DebuggerPresent: Boolean; implementation function ValidDebuggerWorldAddress (p: univ Ptr): Boolean; begin {Address must be even and somewhere within addressable RAM or ROM.} ValidDebuggerWorldAddress := not ODD(ORD(p)) and (ORD(p) >= 0) and (ORD(p) < ORD(MFTopMem)); end; type LongPtr = ^Longint; IntPtr = ^Integer; PtrPtr = ^Ptr; function GetVBR: Ptr; inline $7008, {MOVEQ #$EnterSupervisorMode,D0} $A08D, {_DebugUtil} $4E7A, $8801, {MOVEC VBR,A0} $46C0, {MOVE D0,SR ;restore user mode} $2E88; {MOVE.L A0,(A7)} function ABZMonIsLoaded: Boolean; const _DebugUtil = $A08D; _Unimplemented = $A89F; var VBR: Ptr; vectorPtr: PtrPtr; codePtr: LongPtr; err: OSErr; begin {Alain BirtzÕs ABZmon doesnÕt use MacJmp at all. In fact, it doesnÕt even use} {the trap dispatcher table. Instead, it patches the trap dispatcher! The hint for} {finding this, aside from not finding it anywhere else, is that ABZmon defines} {a private trap _DebugNum $AAFF - this has reserved bit 9 set. ABZmonÕs trap} {dispatcher can be identified by its first instruction, ORI #$700,SR. In hex, this} {is $007C0700.} if GetOSTrapAddress(_DebugUtil) = GetToolTrapAddress(_Unimplemented) then VBR := Ptr(0) else begin if DebuggerGetMax >= 8 then VBR := GetVBR else VBR := Ptr(0); end; if ValidDebuggerWorldAddress(VBR) then begin vectorPtr := PtrPtr(ORD(VBR) + $28); codePtr := LongPtr(vectorPtr^); ABZMonIsLoaded := ValidDebuggerWorldAddress(codePtr) & (codePtr^ = $007C0700); end else ABZMonIsLoaded := False; end; {$IFC (UNDEFINED DebuggerTest_Signature) | DebuggerTest_Signature} function NonStandardDebuggerKind (entry: univ Ptr): DebuggerKind; begin NonStandardDebuggerKind := debuggerKindOther; {If we canÕt decideÉ} {JasikÕs ÒThe DebuggerÓ doesnÕt have a world pointer. Its distinguishing} {feature is a test for whether it was entered via an F-line trap, by executing} {the instruction CMPI #10,DSErrCode. In hex this is $0C7800100AF0.} if (LongPtr(entry)^ = $0C780010) and (IntPtr(ORD(entry) + SIZEOF(Longint))^ = $0AF0) then NonStandardDebuggerKind := debuggerKindJasik else {Add other tests as needed.} ; end; {$ENDC} {This is based on info from ÒMacsBug Reference and Debugging Guide for MacsBug version 6.2Ó} {The MacsBug reference doesnÕt mention that the ROM debugger masquerades as a real debugger.} {Because the ROM debugger doesnÕt have a ÒworldÓ pointer, we have to do some extra checks.} procedure GetDebuggerInfo (var present, active: Boolean; var kind: DebuggerKind; var signature: DebuggerSignature); const {The first and current universal ROM is rev 1660. Assume} {that future universal ROMs will have higher rev numbers.} UnivROMVersion = 1660; MacJmp = $120; Debug32Flags = $BFF; ROMBase = $2AE; DebugInstalledFlagBit = 5; DebugActiveFlagBit = 7; Megabyte = $100000; {The following gestalt selectors are from Rene G.A. RosÕ SGSL.} gestaltEnablerAttr = 'bugy'; {32-bit System Enabler [1.0]} gestaltEnabler32bit = 7; {32-bit enabler present} type PtrPtr = ^Ptr; IntPtr = ^Integer; SigPtr = ^DebuggerSignature; var err: OSErr; gestaltResult: Longint; MM32Bit, univROM, apple32BitEnabler, broken: Boolean; debugFlagsAddr: Ptr; debugEntryAddr, debugWorldAddr, ROMBaseAddr: Ptr; begin err := Gestalt(gestaltAddressingModeAttr, gestaltResult); MM32Bit := (err = noErr) & BTST(gestaltResult, gestalt32BitAddressing); err := Gestalt(gestaltROMVersion, gestaltResult); UnivROM := (err = noErr) & (gestaltResult >= UnivROMVersion); err := Gestalt(gestaltEnablerAttr, gestaltResult); apple32BitEnabler := (err = noErr) & BTST(gestaltResult, gestaltEnabler32bit); {According to the reference, debugger flags are located in the high byte of} {MacJmp unless the machine is 32-bit capable, in which case they move to} {$BFF. IÕm not sure I believe that the 32-bit enablers (ConnectixÕs MODE32} {and AppleÕs 32-bit System Enabler) report the right thing w.r.t. 32-bit capability.} {Clearly, if the machine is running in 32-bit mode, itÕs 32-bit capable even under} {the enablers. But when running under a 32-bit enabler in 24-bit mode, the enabler} {would seem to be obliged to report 32-bit capability. In this state, I wouldnÕt expect} {the enabler to put up enough of a charade to move the debugger flags Ñ theyÕd almost} {certainly end up in the high byte of MacJmp. Also, AppleÕs enabler is damaged in} {the opposite case Ñ the debugger traps still look at the high byte of MacJmp even in} {32-bit mode. This requires a special test to pretend thereÕs no debugger present under} {AppleÕs 32-bit System Enabler in 32-bit addressing mode; 24-bit mode is OK.} broken := apple32BitEnabler and MM32Bit; if not broken then begin if MM32Bit or UnivROM then debugFlagsAddr := Ptr(Debug32Flags) else debugFlagsAddr := Ptr(MacJmp); present := BTST(debugFlagsAddr^, DebugInstalledFlagBit); active := BTST(debugFlagsAddr^, DebugActiveFlagBit); end else begin present := False; active := False; end; if present then begin debugEntryAddr := StripAddress(PtrPtr(MacJmp)^); ROMBaseAddr := StripAddress(PtrPtr(ROMBase)^); if ORD(debugEntryAddr) > ORD(ROMBaseAddr) then {Could be the ROM debuggerÉ} if MM32Bit then begin {In 32-bit mode, any address in or beyond ROM is not in RAM.} present := False; Exit(GetDebuggerInfo); end else if ORD(debugEntryAddr) <= ORD(ROMBaseAddr) + Megabyte then begin {In 24-bit mode, the ROM gets 1MB and can be followed by RAM.} present := False; Exit(GetDebuggerInfo); end; {$IFC (UNDEFINED DebuggerTest_Signature) | DebuggerTest_Signature} debugWorldAddr := PtrPtr(ORD(debugEntryAddr) - SIZEOF(Ptr))^; if ValidDebuggerWorldAddress(debugWorldAddr) then signature := SigPtr(debugWorldAddr)^ else signature := '??'; case Integer(signature) of $4D54: {MT} kind := debuggerKindMacsBug; {¥ This is from memory; I _think_ TMON registers itself this wayÉ} $5748: {WH} kind := debuggerKindTMON; otherwise kind := NonStandardDebuggerKind(debugEntryAddr); end; {$ENDC} end {Alain BirtzÕs ABZmon doesnÕt put anything in MacJmp, but patches the trap dispatcher.} else if ABZMonIsLoaded then begin kind := debuggerKindABZmon; {$IFC (UNDEFINED DebuggerTest_Signature) | DebuggerTest_Signature} signature := '??'; {$ENDC} present := True; end else {No debugger present.} begin kind := debuggerKindNone; {$IFC (UNDEFINED DebuggerTest_Signature) | DebuggerTest_Signature} signature := ' '; {$ENDC} end; end; function DebuggerPresent: Boolean; var present, active: Boolean; kind: DebuggerKind; {this never gets a value} signature: DebuggerSignature; {this never gets a value} begin GetDebuggerInfo(present, active, kind, signature); DebuggerPresent := present; end; end. Dave - -- CPU Cycles: Use them now or lose them forever... --------------------------- >From bb@lightside.com (Bob Bradley) Subject: Q: Converting PB to FSSpec Date: Fri, 22 Jul 1994 08:56:47 -0800 Organization: SS Software Inc. I'm writing an application that needs to process all files/folders in a folder/disk. I have this much so far (hasn't been tested) that I've mostly copied & modified from DragonSmith and DropShell 2.0 to make them work FSSpec's: OSErr FSpProcessDirectoryContents( FSSpec *directory, FSSpecList fileList, Boolean addDirectories, Boolean lookInsideDirectories, Boolean skipOnError ) { OSErr error = noErr; CInfoPBRec pb; short i; Str63 name; Boolean keepGoing; long directoryID; FSSpec file; error = FSpGetDirectoryID( directory, &directoryID ); if( error != noErr ) return( error ); pb.hFileInfo.ioCompletion = NULL; pb.hFileInfo.ioNamePtr = &name[0]; for( i = 1, keepGoing = TRUE; keepGoing; i++ ) { pb.hFileInfo.ioVRefNum = directory->vRefNum; pb.hFileInfo.ioDirID = directoryID; pb.hFileInfo.ioFDirIndex = i; error = PBGetCatInfoSync( &pb ); if( error == noErr ) { // Right here I need something to convert the parameter block to // an FSSpec for this item in the directory. So I can pass it // my routine that either adds it to the FSSpec List (if it's a // file) or calls this routine again (if it's a folder). } else if( error == fnfErr || !skipOnError ) { keepGoing = FALSE; } } if( error == fnfErr ) error = noErr; return( error ); } Can I just copy the pb->h.fileParam.ioNamePtr, pb->c.hFileInfo.ioFlParID, and pb.hFileInfo.ioVRefNum fields of the parameter block to the the FSSpec? or do I need to do some other stuff? Do I need to any special handling of alias's? If you find errors in the above routine, I'd like to know about that too. +++++++++++++++++++++++++++ >From woody@alumni.caltech.edu (William Edward Woody) Date: 24 Jul 1994 19:37:26 GMT Organization: California Institute of Technology, Alumni Association > FSSpec file; > > error = FSpGetDirectoryID( directory, &directoryID ); > if( error != noErr ) return( error ); > pb.hFileInfo.ioCompletion = NULL; > pb.hFileInfo.ioNamePtr = &name[0]; > for( i = 1, keepGoing = TRUE; keepGoing; i++ ) > { > pb.hFileInfo.ioVRefNum = directory->vRefNum; > pb.hFileInfo.ioDirID = directoryID; > pb.hFileInfo.ioFDirIndex = i; > error = PBGetCatInfoSync( &pb ); > if( error == noErr ) > { > > // Right here I need something to convert the parameter block to > // an FSSpec for this item in the directory. So I can pass it > // my routine that either adds it to the FSSpec List (if it's a /* * Then there's my favorite way to do this */ FSMakeFSSpec(directory->vRefNum,directoryID,pb.hFIleInfo.ioNamePtr,&file); /* * Or something like that, your milege may vary. */ > // file) or calls this routine again (if it's a folder). > > } I hope this helps. Like Apple says: Don't build the FSSpec by hand yourself. Instead, use FSMakeFSSpec() [IM VI Ch 25, pg 30] to do the dirty work. - Bill -- - William Edward Woody | Disclamer: woody@alumni.cco.caltech.edu | "He who knows does not speak; - In Phase Consulting | He who speaks does not know." 337 West California #4; Glendale, CA 91203 | - Lao Tzu +++++++++++++++++++++++++++ >From mclow@san_marcos.csusm.edu (Marshall Clow) Date: Sat, 23 Jul 1994 15:40:48 -0800 Organization: Aladdin Systems In article , bb@lightside.com (Bob Bradley) wrote: > I'm writing an application that needs to process all files/folders in a > folder/disk. > > I have this much so far (hasn't been tested) that I've mostly copied & > modified from DragonSmith and DropShell 2.0 to make them work FSSpec's: > I always like to see people using DropShell! I will admit to being a little confused, though. The folder walking code in DropShell uses FSSpecs already, so I don't know what modifications you need to make. [ start of included code deleted ] > error = PBGetCatInfoSync( &pb ); > if( error == noErr ) > { > > // Right here I need something to convert the parameter block to > // an FSSpec for this item in the directory. So I can pass it > // my routine that either adds it to the FSSpec List (if it's a > // file) or calls this routine again (if it's a folder). > [ end of included code deleted ] > > Can I just copy the pb->h.fileParam.ioNamePtr, pb->c.hFileInfo.ioFlParID, > and pb.hFileInfo.ioVRefNum fields of the parameter block to the the > FSSpec? or do I need to do some other stuff? Do I need to any special > handling of alias's? Well, let's take your q's one at a time. 1) You _can_ just copy the relevant fields of the param block into an FSSpec, and go from there. This is what the DropShell does, and it will work. However, Apple has advised against building FSSpecs by hand, and recomends calling FSMakeFSSpec instead. 2) If you want to resolve alias files while you are walking the file tree, you can just call ResolveAliasFile () which will do all the alias traversal for you. _However_, you need to ensure that your loop will terminate. Imagine the following case: You have a folder "one" Inside it is a folder "two" inside it is a file "three" and a file "four", which is an alias to "one". Have fun. -- Marshall -- Marshall Clow Aladdin Systems mclow@san_marcos.csusm.edu --------------------------- >From afrancke@netcom.com (Andrew Francke) Subject: Q: Reentrancy and PowerMac Runtime Model Date: Mon, 11 Jul 1994 03:13:46 GMT Organization: Netcom Online Communications Services (408-241-9760 login: guest) Even after scouring IM:PowerPC System Software, I yet labor under the thick delusion that there is no way to prevent concurrency/reentrancy on the PowerMac running native code. Whereas poking the SR worked just fine before to keep interrupt code from unhappily butting in while regular code was updating head and tail pointers on lists, there seems to be no such mention of an equivalent "Critical Section" API on PowerMac. Yea, verily, I believe it is not possible and am now contemplating abandoning all Macintosh development. Say it ain't so. P.S. While you're at it, tell me how it's possible to page-lock an arbitrary range of memory while running native. Does the VM API described in IM:Memory still apply? Or is it just, "tough luck -- you'll have to put everything you want in the system heap." Finally, when (if ever) is the device driver interface going to be revved so that drivers can be written native? IMHO, this is the dirtiest secret kept by the Mac rags as device drivers far and away make the machine. +++++++++++++++++++++++++++ >From rmah@panix.com (Robert Mah) Date: Mon, 11 Jul 1994 01:04:22 -0500 Organization: One Step Beyond afrancke@netcom.com (Andrew Francke) wrote: ) Even after scouring IM:PowerPC System Software, I yet labor under the ) thick delusion that there is no way to prevent concurrency/reentrancy ) on the PowerMac running native code. Whereas poking the SR worked just ) fine before to keep interrupt code from unhappily butting in while ) regular code was updating head and tail pointers on lists, there seems ) ... What an extremely nasty way to check for interupts :-) I simply use the OS queue routines. Enqueue and Dequeue both disable interupts so you can be SURE you're VBL's, callbacks and whatnot all work nicely together. Cheers, Rob _____________________________________________________________________ Robert S. Mah : Macintosh software development : 212.947.6507 One Step Beyond : and network consulting : rmah@panix.com +++++++++++++++++++++++++++ >From zstern@adobe.com (Zalman Stern) Date: Mon, 11 Jul 1994 08:26:28 GMT Organization: Adobe Systems Incorporated Andrew Francke writes > Even after scouring IM:PowerPC System Software, I yet labor under the > thick delusion that there is no way to prevent concurrency/reentrancy > on the PowerMac running native code. Whereas poking the SR worked just > fine before to keep interrupt code from unhappily butting in while > regular code was updating head and tail pointers on lists, there seems > to be no such mention of an equivalent "Critical Section" API on > PowerMac. Yea, verily, I believe it is not possible and am now > contemplating abandoning all Macintosh development. Say it ain't so. For updating queues in native code, the load-reserved/store-conditional mechanism is what you want to use. The mnemonics are lwarx and stwcx. respectively. There are examples on their usage in Appendix G of the MPC601 User's Manual. > P.S. While you're at it, tell me how it's possible to page-lock an > arbitrary range of memory while running native. Does the VM API > described in IM:Memory still apply? It certainly should. (I.e. I haven't tried this, but I expect there's a moderate amount of 68k Mac software that would break if things did not work this way.) -- Zalman Stern zalman@adobe.com (415) 962 3824 Adobe Systems, 1585 Charleston Rd., POB 7900, Mountain View, CA 94039-7900 `Wait a second! This is just an octahedron suspended in blue liquid.' - JT +++++++++++++++++++++++++++ >From mxmora@unix.sri.com (Matthew Xavier Mora) Date: Mon, 11 Jul 1994 14:32:15 -0700 Organization: SRI International In article , afrancke@netcom.com (Andrew Francke) wrote: > on the PowerMac running native code. Whereas poking the SR worked just > fine before to keep interrupt code from unhappily butting in while > regular code was updating head and tail pointers on lists, there seems > to be no such mention of an equivalent "Critical Section" API on > PowerMac. This is one thing that they say will die a horrible death in Copland. Do not set SR! > you'll have to put everything you want in the system heap." Finally, > when (if ever) is the device driver interface going to be revved so > that drivers can be written native? IMHO, this is the dirtiest secret > kept by the Mac rags as device drivers far and away make the machine. You'll have to wait for Copland release for the new Native Driver support. Write them at their Applink address if you want more information. I don't know the address offhand. Its microkernel.. Xavier -- Matt Mora mxmora@unix.sri.com Testing Neswatcher +++++++++++++++++++++++++++ >From quinn@cs.uwa.edu.au (Quinn "The Eskimo!") Date: Tue, 12 Jul 1994 10:45:59 +0800 Organization: Department of Computer Science, The University of Western Australia In article , afrancke@netcom.com (Andrew Francke) wrote: >Finally, >when (if ever) is the device driver interface going to be revved so >that drivers can be written native? IMHO, this is the dirtiest secret >kept by the Mac rags as device drivers far and away make the machine. You can write your drivers native, it's just that you have to have some 68K glue at the front and thereby take a mixed-mode switch on every entry to them. But even if there was a native API you'd still be taking a mixed-mode switch because the Device Manager (including the bit that fields interrupts) is emulated. So if you do a *lot* of work in your device driver then writing it native would make sense. All this mess is going to be sorted out in Copland. Which means that a lot of device drivers are going to have to be rewritten. -- Quinn "The Eskimo!" "Support HAVOC!" Department of Computer Science, The University of Western Australia Who missed that session at WWDC and is desperately seeking the presentation CD. +++++++++++++++++++++++++++ >From steele@isi.edu (Craig Steele) Date: Tue, 12 Jul 1994 12:14:30 -0800 Organization: USC Information Sciences Institute In article , mxmora@unix.sri.com (Matthew Xavier Mora) writes: > You'll have to wait for Copland release for the new Native Driver > support. Write them at their Applink address Judging from the preliminary draft of "Designing PCI Cards and Drivers for Power Macintosh Computers" that arrived in my mailbox yesterday, bits of the future are coming a bit sooner. A final PCI Card Developer's Kit for PowerMacs is said to be scheduled for APDA release in the "summer of 1994." The PCI runtime drivers use native interfaces. You might be able to get a copy of the preliminary draft by contacting them at apple.pci.applelink.apple.com. Craig S. Steele, steele@isi.edu - Not yet Institutionalized +++++++++++++++++++++++++++ >From telesis@ecf.toronto.edu (Telesis North) Date: Wed, 13 Jul 1994 04:19:47 GMT Organization: telesis north & screen door company In article , Quinn "The Eskimo!" wrote: >All this mess is going to be sorted out in Copland. Which means that a >lot of device drivers are going to have to be rewritten. Actually, _all_ the device drivers are going to have to be re-written (or break). That was my favourite quote out of the WWCC, "Under Copland, (current) 68K device drivers will not run." Heh. -- Roger Pantos Telesis North, Inc. telesisnorth Mac Software Guy telesis@ecf.toronto.edu (AppleLink) Contrary to popular belief, green eggs & ham suck big time. +++++++++++++++++++++++++++ >From quinn@cs.uwa.edu.au (Quinn "The Eskimo!") Date: Thu, 14 Jul 1994 11:20:10 +0800 Organization: Department of Computer Science, The University of Western Australia In article , telesis@ecf.toronto.edu (Telesis North) wrote: >In article , >Quinn "The Eskimo!" wrote: >>All this mess is going to be sorted out in Copland. Which means that a >>lot of device drivers are going to have to be rewritten. > >Actually, _all_ the device drivers are going to have to be re-written (or >break). That was my favourite quote out of the WWCC, > > "Under Copland, (current) 68K device drivers will not run." Well this is an interesting question. I didn't catch that session at WWDC but I can see no reason why software only device drivers (such .Notify and .Reminder) couldn't be supported. These are just using the Device Manager as a kludgy share library system that gives you non-interrupt time. So was there any comment about non-hardware device drivers? >Roger Pantos Hi Roger! Maybe if your real name was something other that Telesis North I'd catch your postings more often (: -- Quinn "The Eskimo!" "Support HAVOC!" Department of Computer Science, The University of Western Australia +++++++++++++++++++++++++++ >From rang@winternet.com (Anton Rang) Date: 14 Jul 1994 04:24:00 GMT Organization: Trillium Research, Inc. In article afrancke@netcom.com (Andrew Francke) writes: >Even after scouring IM:PowerPC System Software, I yet labor under the >thick delusion that there is no way to prevent concurrency/reentrancy >on the PowerMac running native code. You're right! Well, more or less. You can change the SR by going back into 68K code, and since all interrupts are currently dispatched through the emulator, this will block them from being processed until you change the SR back. But (a) this will break, and (b) this will be incredibly slow. Don't do it if you don't have to. >Whereas poking the SR worked just >fine before to keep interrupt code from unhappily butting in while >regular code was updating head and tail pointers on lists Well, in this case you can either (a) call Enqueue/Dequeue, which is slow because of the mode switch but will be atomic, or (b) use a little assembly language to call the lwarx/stwcx instructions. Check your manual for details. >there seems to be no such mention of an equivalent "Critical Section" >API on PowerMac. There will be. Unfortunately, it's not there yet. The hardware is ahead of the software, currently. >P.S. While you're at it, tell me how it's possible to page-lock an >arbitrary range of memory while running native. Does the VM API >described in IM:Memory still apply? Yes, that API still works. (All the current APIs work, actually.) >Finally, when (if ever) is the device driver interface going to be >revved so that drivers can be written native? With the release of PCI-based Macintoshes, at first, and then with the next major system release (for older PowerMacs too presumably). I wish it were sooner, I *hate* debugging my current driver. :) -- Anton Rang (rang@winternet.com) +++++++++++++++++++++++++++ >From telesis@ecf.toronto.edu (Telesis North) Date: Thu, 14 Jul 1994 04:47:49 GMT Organization: Roger @ Telesis North In article , Quinn "The Eskimo!" wrote: > >Well this is an interesting question. I didn't catch that session at WWDC >but I can see no reason why software only device drivers (such .Notify and >.Reminder) couldn't be supported. These are just using the Device Manager >as a kludgy share library system that gives you non-interrupt time. So >was there any comment about non-hardware device drivers? I don't remember any; I just remember the speaker (Russell?) being pretty blunt about it. My understanding is that they're planning on ripping out the entire toolbox-level I/O architecture, along with the 68K-centric interrupt services, and heaving it off the dock with a huge sigh of relief. (It will of course be replaced with a spiffy new re-entrant driver model with a message-passing interface to the microkernel that will make life wonderful for everyone, once they've re-written their drivers.) I agree with your point, though. I'd say an easy 50% of the drivers running on my machine are just there to provide user interface hacks (or other software-only goodies). Come to think of it, it's probably mostly intercine warfare between the Now Utilities and everyone else... The problem is that most of these are so skanky, I'm not sure how far you'd have to go, emulation-wise, to get any level of backward compatibility. I suppose that one could write an early-load INIT that patched OpenDriver(), GetDCtlEntry() and friends, and used a faceless background app to provide non-interrupt time to the drivers in the custom entry table, but you'd still have people looking for familiar things in the global Unit Table in the Toolbox space, not to mention making asynchronous PBControl calls with oddball semantics... I shudder even to think about it. :-) Copland is going to break a lot of software, in the name of performance. Not necessarily straight-line application software, but lots of stand-alone gadgets and integrated systems. (Anyone holding out any hope for FaxSTF?) Should Apple devote engineer and QA time to emulating the old driver model? Tough question. I know I'm not going to - I'm going to re-write our drivers (and turn them into processes, most likely). >Hi Roger! Maybe if your real name was something other that Telesis North >I'd catch your postings more often (: Yeah, yeah. :-) I still get my news fix through an ancient Unix shell account that we pay a university through the nose for. I'm thinking that the time I could spend reading through the man pages might be better spent pestering people to get my Mac IP-connected. (Still, beats chipping out TCP packets on stone tablets, which is what we did in the old days...) -- Roger Pantos Telesis North, Inc. telesisnorth Mac Software Guy telesis@ecf.toronto.edu (AppleLink) I can think of nothing more odious than a philosophy that forces its beliefs or its conscriptions on those who are unwilling or uninterested in having them. +++++++++++++++++++++++++++ >From chewey@nesw.mv.com (Matthew E. Axsom) Date: Fri, 15 Jul 1994 13:30:42 GMT Organization: New England Software Works In article , quinn@cs.uwa.edu.au (Quinn "The Eskimo!") wrote: > In article , telesis@ecf.toronto.edu (Telesis > North) wrote: > > >In article , > >Quinn "The Eskimo!" wrote: > >>All this mess is going to be sorted out in Copland. Which means that a > >>lot of device drivers are going to have to be rewritten. > > > >Actually, _all_ the device drivers are going to have to be re-written (or > >break). That was my favourite quote out of the WWCC, > > > > "Under Copland, (current) 68K device drivers will not run." > > Well this is an interesting question. I didn't catch that session at WWDC > but I can see no reason why software only device drivers (such .Notify and > .Reminder) couldn't be supported. These are just using the Device Manager > as a kludgy share library system that gives you non-interrupt time. So > was there any comment about non-hardware device drivers? > I believe that they used that as a blanket statement at first and later backed away from that and said that the current driver model would still run as long as it was a "softwre driver" (e.g. .Reminder or .Notify) and not a "hardware driver". I believe they said that as long as it doesn't touch the hardware directly, the old drivers could still be used. -Chewey struct Matthew: E, Axsom { //chewey@nesw.mv.com Matthew(void) : E(), Axsom() {} Boolean macSoftwareEngineer(long future) {return future==Random();} Boolean newEnglandSoftwareWorks(StringPtr name) {return true;} }; +++++++++++++++++++++++++++ >From absurd@apple.com (Tim Dierks) Date: Fri, 22 Jul 1994 23:27:05 GMT Organization: Apple Computer, Inc. In article , telesis@ecf.toronto.edu (Telesis North) wrote: > In article , > Quinn "The Eskimo!" wrote: > > > >Well this is an interesting question. I didn't catch that session at WWDC > >but I can see no reason why software only device drivers (such .Notify and > >.Reminder) couldn't be supported. These are just using the Device Manager > >as a kludgy share library system that gives you non-interrupt time. So > >was there any comment about non-hardware device drivers? > > I don't remember any; I just remember the speaker (Russell?) being > pretty blunt about it. My understanding is that they're planning on > ripping out the entire toolbox-level I/O architecture, along with > the 68K-centric interrupt services, and heaving it off the dock with > a huge sigh of relief. (It will of course be replaced with a spiffy > new re-entrant driver model with a message-passing interface to the > microkernel that will make life wonderful for everyone, once they've > re-written their drivers.) > > I agree with your point, though. I'd say an easy 50% of the drivers > running on my machine are just there to provide user interface hacks > (or other software-only goodies). Come to think of it, it's probably > mostly intercine warfare between the Now Utilities and everyone else... > > The problem is that most of these are so skanky, I'm not sure how far > you'd have to go, emulation-wise, to get any level of backward > compatibility. Copland will support the Device manager driver model for dispatching to old-style drivers; this level of compatibility should allow many drivers to continue to work, especially those which are software-only, and just manipulate data or dispatch to other drivers or toolboxes. Of course, this doesn't guarantee the software inside the driver will still work (depending on its assumptions), but we'll try to support the mechanism as best we can. 68K drivers which touch hardware or which get invoked to handle hardware interrupts will most likely not be compatible. > Copland is going to break a lot of software, in the name of > performance. Not necessarily straight-line application software, > but lots of stand-alone gadgets and integrated systems. (Anyone > holding out any hope for FaxSTF?) > > Should Apple devote engineer and QA time to emulating the old driver > model? Tough question. I know I'm not going to - I'm going to re-write > our drivers (and turn them into processes, most likely). Copland won't be 100% compatible, but a lot of the stuff we break we'll break because it's fundamentally incompatible with progress; stuff that's bad, but not that bad, we'll just have to see... > Roger Pantos Telesis North, Inc. telesisnorth -- Tim Dierks absurd@apple.com --------------------------- >From stk@uropax.contrib.de (Stefan Kurth) Subject: Std filter proc trashes register D3! Date: 18 Jul 1994 14:40:50 +0200 Organization: Contributed Software GbR Just discovered another system software bug: the standard filter proc (the one that you get with GetStdFilterProc() ) distroys the contents of the D3 register. Took me quite some time to figure out why one my variables kept changing all by itself... Is this a known bug? If not, how do I go about reporting it to Apple? ________________________________________________________________________ Stefan Kurth Berlin, Germany stk@contrib.de +++++++++++++++++++++++++++ >From D.A.G.Gillies@bradford.ac.uk (David Gillies) Date: Mon, 18 Jul 1994 15:13:25 GMT Organization: Unseen University, Ankh-Morpork In article <30dt8i$32d@uropax.contrib.de> stk@uropax.contrib.de (Stefan Kurth) writes: >Just discovered another system software bug: the standard filter proc >(the one that you get with GetStdFilterProc() ) distroys the contents >of the D3 register. Took me quite some time to figure out why one my >variables kept changing all by itself... > >Is this a known bug? If not, how do I go about reporting it to Apple? > This definitely sounds like a bug. If nothing else, the compiler should make callbacks safe by padding where necessary with MOVEM. It's only D0-D2 and A0/A1 that routines are meant to be allowed to stamp on, and compilers should recognize this and guard against it. I might be wrong, but this does seem suspicious. Personally I hate the standard filter proc, but I always prefer to roll my own. ______________________________________________________________________ David A. G. Gillies (D.A.G.Gillies@bradford.ac.uk) University of Bradford, Bradford, West Yorkshire, England (c) 1994 Wittgenstein and The Furniture Depository of The Living Dead A little learning is a dangerous thing - but not half as dangerous as a lot of ignorance. - ---------------------REPLIES VIA EMAIL PLEASE----------------------- _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ +++++++++++++++++++++++++++ >From stk@uropax.contrib.de (Stefan Kurth) Date: 19 Jul 1994 01:16:49 +0200 Organization: Contributed Software GbR In article <1994Jul18.151325.8525@bradford.ac.uk>, David Gillies wrote: > In article <30dt8i$32d@uropax.contrib.de> stk@uropax.contrib.de > (Stefan Kurth) writes: > > > Is this a known bug? If not, how do I go about reporting it to Apple? > > This definitely sounds like a bug. Sure it is - my question was if it is a _known_ bug... :-) > If nothing else, the compiler should make callbacks safe by padding where > necessary with MOVEM. It's only D0-D2 and A0/A1 that routines are meant > to be allowed to stamp on, and compilers should recognize this and guard > against it. In this case it's not the compiler's job to save registers (I mean, not _my_ compiler's; it would have been the job of whatever compiler Apple used to compile their system software). The standard filter proc should save the registers that it uses; however, it saves only D4-D7, but also uses D3. > Personally I hate the standard filter proc, but I always prefer to roll > my own. Would you explain why? I have found it extremely handy. It does a lot of work for you. ________________________________________________________________________ Stefan Kurth Berlin, Germany stk@contrib.de +++++++++++++++++++++++++++ >From Alexander M. Rosenberg Date: Tue, 19 Jul 1994 02:20:19 GMT Organization: Hackers Anonymous In article <30dt8i$32d@uropax.contrib.de> Stefan Kurth, stk@uropax.contrib.de writes: > Just discovered another system software bug: the standard filter proc > (the one that you get with GetStdFilterProc() ) distroys the contents > of the D3 register. Took me quite some time to figure out why one my > variables kept changing all by itself... > > Is this a known bug? If not, how do I go about reporting it to Apple? Yes. Thank you for taking the time to track it down. I believe that it is under consideration for our next System Update release. - ------------------------------------------------------------------------- - Alexander M. Rosenberg - INTERNET: alexr@apple.com - Yoyodyne - - 330 Waverley St., Apt B - UUCP:ucbvax!apple!alexr - Propulsion - - Palo Alto, CA 94301 - - Systems - - (415) 329-8463 - Nobody is my employer so - :-) - - - nobody cares what I say. - - +++++++++++++++++++++++++++ >From David A Lyons Date: Tue, 19 Jul 1994 06:00:07 GMT Organization: Apple Computer, Inc. In article <30dt8i$32d@uropax.contrib.de> Stefan Kurth, stk@uropax.contrib.de writes: > Just discovered another system software bug: the standard filter proc > (the one that you get with GetStdFilterProc() ) distroys the contents > of the D3 register. Took me quite some time to figure out why one my > variables kept changing all by itself... > > Is this a known bug? If not, how do I go about reporting it to Apple? It's a known bug in ROMs earlier than the Quadra 840av/660av; for now you'll have to work around it in your application. Dave Lyons Mr Tangent +++++++++++++++++++++++++++ >From jonasw@lysator.liu.se (Jonas Wallden) Date: 19 Jul 1994 16:59:31 GMT Organization: (none) David A Lyons writes: >In article <30dt8i$32d@uropax.contrib.de> Stefan Kurth, >stk@uropax.contrib.de writes: >> Just discovered another system software bug: the standard filter proc >> (the one that you get with GetStdFilterProc() ) distroys the contents >> of the D3 register. Took me quite some time to figure out why one my >> variables kept changing all by itself... >> >> Is this a known bug? If not, how do I go about reporting it to Apple? > >It's a known bug in ROMs earlier than the Quadra 840av/660av; for now >you'll have to work around it in your application. > >Dave Lyons >Mr Tangent On a related subject: I installed a memory grow proc in an application that uses a small heap, and that also uses StandardFile to select folders. I noticed that my grow proc was called while the SF dialog was being shown, and that SF tried to allocate a large memory block (size > 64 Kb). Of course it failed to find the free memory but everything works ok anyway. Is this just some cache memory that it tries to allocate for the fancy color icons used by Hardware System Update 3.0? I will have to check again to make sure it's not one of my system extensions playing a trick on me. -- Jonas Wallden -- -- Jonas Wallden -- Internet: jonasw@lysator.liu.se -- AppleLink: sw1369 -- +++++++++++++++++++++++++++ >From dean@genmagic.com (Dean Yu) Date: 19 Jul 1994 18:35:23 GMT Organization: General Magic, Inc. In article <30dt8i$32d@uropax.contrib.de>, stk@uropax.contrib.de (Stefan Kurth) wrote: > Just discovered another system software bug: the standard filter proc > (the one that you get with GetStdFilterProc() ) distroys the contents > of the D3 register. Took me quite some time to figure out why one my > variables kept changing all by itself... > > Is this a known bug? If not, how do I go about reporting it to Apple? This is a known bug. (Well, I knew about it when I was there...) I seem to remember writing some inline code to work around this problem, but I don't remember what that was for. -- Dean Yu Negative Ethnic Role Model General Magic, Inc. --------------------------- >From Jim Conner Subject: Which NIM for serial port info? Date: 25 Jul 1994 02:13:58 GMT Organization: Cornell University Hello, I have been developing a somewhat specialized application for analysis of data generated by an instrument in our lab. Currently, the data is taken from the instrument's small display unit and entered by hand into the application. The data is also available from the instrument's RS-232 port. The hope is that this data can be sent directly from the instrument to the Mac by way of one of the Mac's serial ports. I think that I have a grip on the hardware aspect of this connection (wiring one of the Mac's RS-422 serial ports so it looks like RS-232, and making the correct cable to the instrument). I would like to know, though, (1) which New Inside Macintosh book covers serial port manipulations, and (2) if anyone has any other references that have been helpful with this sort of problem. Thanks, Jim Conner +++++++++++++++++++++++++++ >From bierman@caelab1.cae.wisc.edu (Peter Bierman) Date: Sun, 24 Jul 1994 23:43:13 -0500 Organization: The Metropolis BBS <614/846-1911> Info-Mac on CD! In article <30v756$ghq@newsstand.cit.cornell.edu>, Jim Conner wrote: > I would like to know, > though, (1) which New Inside Macintosh book covers serial port > manipulations, and (2) if anyone has any other references that have been > helpful with this sort of problem. > NIM: Devices. (I don't even know if it's out yet) Chapter 5. Many people suggest "Terminal 2.2" as a great source for example code, in C. -Peter -- Peter Bierman |"Sometimes I think that the surest sign bierman@caelab1.cae.wisc.edu | that intelligent life exists elsewhere The Metropolis 614/846-1911 | in the universe is that none of it has 600+MB, 2CDs, 2Lines@14.4 | tried to contact us." --Calvin --------------------------- End of C.S.M.P. Digest **********************