steig@batcomputer.UUCP (06/11/87)
I am writing a program in Lightspeed C that asks the user for a filename using the standard file package and then processes the text in that file using some of the stdio C routines. I use fopen() to open the file. fopen() requires the pathname of the file, but SFGetFile and SFPutFile only return the filename and the working directory reference number. How do I obtain the pathname of the file? -- |Mark J. Steiglitz |Bitnet: steig@crnlthry, araj@crnlvax5 | |USnail: 66 Steiglitz Road |Arpanet: steig@tcgould.tn.cornell.edu | | Liberty, NY 12754 | araj@vax5.ccs.cornell.edu | | |Usenet: steig@batcomputer.tn.cornell.edu.uucp |
clive@drutx.ATT.COM (Clive Steward) (06/11/87)
in article <1345@batcomputer.tn.cornell.edu>, steig@batcomputer.tn.cornell.edu (Mark J. Steiglitz) says: > > > I am writing a program in Lightspeed C that asks the user for a filename > using the standard file package and then processes the text in that file > using some of the stdio C routines. I use fopen() to open the file. > > fopen() requires the pathname of the file, but SFGetFile and SFPutFile only > return the filename and the working directory reference number. How do I > obtain the pathname of the file? Welcome to the party, Mark. I just doped this out by fighting with the HFS file system stuff in inside Mac IV for a whole night, and then snooping someone elses code after all the heavy stuff got me nothing(!). Getting the pathname is possible (LSC editor does it, if you ask), but clearly involves traipsing the PBGetCatInfo trail. Maybe someone who has done this successfully would post some code; it would be enlightening for planning how to effectively do other things. But apparently the real answer to your question is simple. It means taking Inside Mac's advice about not using full paths, but rather depending on the working directory system. And also believing what is said about playing fast and loose with vRefNums, which can actually be either Volume or Working Directory references. All it seems you have to do is take the vRefNum that you get back from SFGetFile, and feed that to SetVol before opening the name, e.g.: SFGetFile (SFPwhere, "\p", NULL, 1, typelist, NULL, &reply); if (reply.good) { SetVol ("\p", reply.vRefNum); /* set Working Dir, actually */ if ((fp = fopen (PtoCstr (reply.fname), "r - or whatever")) != NULL ) { ... } ... } It's not Unix, but thinking of the SetVol as a kind of chdir will help. The apparentlys and seems in the above are because the method works flawlessly for me, except for one case. In a program I'm working on, I do an SFPutFile right after the above fragment. This works fine, except, _only_ when there needs to be a disk swap to pick up the SFPutFile package. Then SFPutFile becomes confused, and doesn't show the (proper or any) files in it's dialog. I read in the last week a note that there's a bug in SFPutFile which sounds like it's probably this, so probably there's not really any fault in the above. (I was using system 3.2 at the time, think this is fixed in 4.1, but haven't tried to see yet). Would someone like to elaborate about the bug, and how to get around it (since users may not have the updated system)? Clive Steward
dwb@apple.UUCP (06/12/87)
In article <1345@batcomputer.tn.cornell.edu> steig@tcgould.tn.cornell.edu.UUCP (Mark J. Steiglitz) writes: >fopen() requires the pathname of the file, but SFGetFile and SFPutFile only >return the filename and the working directory reference number. How do I >obtain the pathname of the file? ... SFGetFile(where, "", NULL, 1, &types, NULL, &reply); if(!reply.good) return GetVol(NULL, &oldVol); /* save def. vol. so we can restore */ SetVol(NULL, reply.vRefNum); /* change default vol. to selected */ fp = fopen(ptocstr(reply.fName), "r"); SetVol(NULL, oldVol); /* restore original def. vol. */ if(!fp) { ... } ... -- David W. Berry dwb@well.uucp dwb@Delphi dwb@apple.com 293-0752@408.MaBell
cute@sphinx.uchicago.edu (John Cavallino) (06/12/87)
It seems that many people are interested in how to do this. I have posted some tested code (in pascal) to comp.sources.mac. It includes a function which takes a volume reference number, a file name and a directory ID and returns the full path. It checks for HFS vs. MFS and does the right thing in either case. It even attempts to salvage things if the file turns out to be too deeply nested for the full path to fit in a pascal string. Use and enjoy. Yours. John C. -- ...ihnp4!gargoyle!sphinx!cute (insert pithy quote here)
lsr@apple.UUCP (Larry Rosenstein) (06/13/87)
In article <204@drilex.UUCP> dricej@drilex.UUCP (Craig Jackson) writes: >this. Does anyone have any working code that they code post? (C, Pascal?) >Does MacApp provide this facility? MacApp doesn't provide this. I wrote some code, which I have included below. (This was taken from an early version of the StdFile MPW tool, which comes with MPW 2.0.) IEString is a string type that is defined in the MPW integrated environment unit. This code doesn't check to see if your final pathname exceeds 255 characters. This code did work, but I don't guarantee that I didn't make any mistakes while pulling it out of the program. Larry Rosenstein UUCP: {sun, voder, nsc, mtxinu, dual}!apple!lsr CSNET: lsr@Apple.com ******************************* VAR gotHFS: BOOLEAN; { Setting the above variable is left as an exercise for the reader. } { Given a working directory refnum, return the volume refnum and dirID. This assumes that HFS is installed on the machine. } FUNCTION GetDirID(VAR vRefnum: INTEGER; VAR dirID: LONGINT): OSErr; VAR pb: WDPBRec; BEGIN WITH pb DO BEGIN ioCompletion := NIL; ioNamePtr := NIL; ioVRefnum := vRefnum; ioWDIndex := 0; ioWDProcID := 0; ioWDVRefnum := vRefnum; END; GetDirID := PBGetWDInfo(@pb, FALSE); vRefnum := pb.ioWDVRefnum; dirID := pb.ioWDDirID; END; { Given a volume refnum and dirID, return name of the volume / folder. This routine assumes that HFS is installed on the machine. } FUNCTION DirID2Name(vRefnum: INTEGER; dirID: LONGINT; VAR name: IEString): OSErr; VAR pb: CInfoPBRec; temp: Str255; err: OSErr; BEGIN name := ''; err := noErr; WITH pb DO BEGIN ioCompletion := NIL; ioNamePtr := @temp; ioVRefnum := vRefnum; ioDrDirID := dirID; END; REPEAT pb.ioFDirIndex := -1; { get info about directory ioDirID } err := PBGetCatInfo(@pb, FALSE); IF err = noErr THEN BEGIN name := Concat(temp, ':', name); IF pb.ioDrDirID = 2 THEN { root directory } pb.ioDrDirID := 0 ELSE pb.ioDrDirID := pb.ioDrParID; END; UNTIL (err <> noErr) | (pb.ioDrDirID = 0); DirID2Name := err; END; { Given a volume or WD refnum, return name of the volume / folder. This can be called whether or not HFS exists. This is the primary procedure that you would call from your program. } FUNCTION GetFolderName(vRefnum: INTEGER; VAR name: IEString): OSErr; VAR pb: CInfoPBRec; temp: Str255; err: OSErr; dirID: LONGINT; i: INTEGER; len: INTEGER; BEGIN name := ''; err := noErr; IF gotHFS THEN { find the dirID, and get the full pathname } BEGIN err := GetDirID(vRefnum, dirID); IF err = noErr THEN GetFolderName := DirID2Name(vRefnum, dirID, name); END ELSE { no HFS, just get the volume name } BEGIN temp := ''; WITH pb DO BEGIN ioCompletion := NIL; ioNamePtr := @temp; ioVRefnum := vRefnum; ioFDirIndex := 0; ioDrDirID := 0; END; err := PBGetVInfo(@pb, FALSE); IF err = noErr THEN name := Concat(temp, ':'); END; GetFolderName := err; END; ***** END OF CODE ***** -- Larry Rosenstein Object Specialist Apple Computer AppleLink: Rosenstein1 UUCP: {sun, voder, nsc, mtxinu, dual}!apple!lsr CSNET: lsr@Apple.com
earleh@dartvax.UUCP (06/14/87)
In article <19339@ucbvax.BERKELEY.EDU>, oster@dewey.soe.berkeley.edu (David Phillip Oster) writes: > > Many people have said they want to see how to work with complete > pathnames to files expressed as strings. Please mention in your > product literature that you are doing this - I won't buy any product > that does. I agree! Byte the bullet, programmers! Use PBOpen, PBRead, PBWrite, and the entire ensemble of IN ROM Macintosh file handling routines to make your code more efficient and also more able to withstand the effects of system upgrades. You don't have to call SetVol(), you don't have to obtain the pathname of the file, and you don't have to worry about what happens to your file connection when a disk gets ejected. Of course, this reduces "portability" but who are we kidding here? A satisfied ROM user. -- ********************************************************************* *Earle R. Horton, H.B. 8000, Dartmouth College, Hanover, NH 03755 * *********************************************************************
clubmac@runx.ips.oz (Macintosh Users Group) (06/17/87)
In article <1345@batcomputer.tn.cornell.edu> steig@tcgould.tn.cornell.edu.UUCP (Mark J. Steiglitz) writes: > >I am writing a program in Lightspeed C that asks the user for a filename >using the standard file package and then processes the text in that file >using some of the stdio C routines. I use fopen() to open the file. > >fopen() requires the pathname of the file, but SFGetFile and SFPutFile only >return the filename and the working directory reference number. How do I >obtain the pathname of the file? >-- Mark, I haven't seen any code to compute a full HFS pathname to a file from it's filename and WDRefNum (Does anyone have code?), but if you use GetVol and SetVol, you shouldn't have any problems. I hope this code segment helps. .... GetVol(NULL,&currVol); /* Get default volume now for restoration after fopen() call */ SetVol(NULL,reply.vRefNum); /* Set default volume to volume abtained from SF{Get,Put}File call */ PtoCstr(reply.fName); /* Convert fName for fopen() call */ fp = fopen(reply.fName,"r"); /* open */ CtoPstr(reply.fName); /* balance PtoCstr() */ SetVol(NULL,currVol); /* restore */ .... Jason Haines Club Mac Macintosh Users Group - Sydney, Australia Snail: Box 213, Holme Building, Sydney University, NSW, 2006, Australia ACSnet: clubmac@runx.ips.oz ARPA: clubmac%runx.ips.oz@seismo.css.gov UUCP:{enea,hplabs,mcvax,prlb2,seismo,ubc-vision,ukc}!munnari!runx.ips.oz!clubmac
rae@unicus.UUCP (Clith de T'nir a.k.a. Reid Ellis) (06/20/87)
In article <6462@dartvax.UUCP> earleh@dartvax.UUCP writes: | | ... Byte the bullet, programmers! Use PBOpen, PBRead, PBWrite, and | the entire ensemble of IN ROM Macintosh file handling routines ... | ... you don't have to | obtain the pathname of the file, and you don't have to worry about what | happens to your file connection when a disk gets ejected. Of course, | this reduces "portability" but who are we kidding here? Um, doesn't this ignore applications where a path is read from a text file? [along the lines of a C compiler's "#include <a:long:path>"] What then? Make the user memorize vRefNums of his folders? :-) Reid +=-- --- "ZOT, YOU JERK!" - Jenny Reid Ellis, aka Clith de T'nir {seismo!mnetor, utzoo!yetti}!unicus!rae (uucp) mnetor!unicus!rae@seismo.css.gov (arpa)
earleh@dartvax.UUCP (Earle R. Horton) (06/22/87)
In article <665@unicus.UUCP>, rae@unicus.UUCP (Clith de T'nir a.k.a. Reid Ellis) writes: > In article <6462@dartvax.UUCP> earleh@dartvax.UUCP writes: > | > | ... Byte the bullet, programmers! Use PBOpen, PBRead, PBWrite, and > | the entire ensemble of IN ROM Macintosh file handling routines ... > | ... you don't have to > | obtain the pathname of the file, and you don't have to worry about what > | happens to your file connection when a disk gets ejected. Of course, > | this reduces "portability" but who are we kidding here? > > Um, doesn't this ignore applications where a path is read from a text > file? [along the lines of a C compiler's "#include <a:long:path>"] What > then? Make the user memorize vRefNums of his folders? :-) No, it does not. A full pathname, if it is valid, will OVERRIDE an explicit volume specification. (IM, volume IV, File Manager chapter.) If I were writing a C compiler, and wanted to handle this sort of thing, this is exactly what I would have the program do: a) Set up a parameter block for dealing with the file b) Put a zero in the ioVRefNum field c) Put the pointer to the full pathname in the ioNamePtr field d) Fill in ioCompletion, ioVersNum, ioMisc, ioPermssn as appropriate e) Call PBOpen to open the sucker. Here is the main point: At no point in this process does my program have any knowledge of the format of the pathname. I do not manipulate the pathname, and I do not attempt to construct the full pathname if I do not have it. If the user obtains a file for me from one of the Standard File Package routines, then the correct thing to do is, in step b), just put in the vRefNum obtained from SFGetFile or whatever. If the USER gives me a pathname, then I use it, as is. Most programs do not need to know the full pathname of a file, they just need a RELIABLE means of gaining access to the file. Using full pathnames on the Mac is not a reliable means of obtaining access to a file, which is why it should only be used in cases like Reid's example, above, where it is absolutely necessary. The information obtained from the Standard File Package routines is sufficient to locate a file correctly on any Macintosh. I do not see why anyone would wish to translate this information into a format which is NOT capable of always locating a file correctly. This is exactly what you do when you attempt to construct a full pathname to a file. This approach may be justified for some applications, but for the enormous majority of applications that are to be used by ordinary humans, it introduces the possibility of a run time error which is simply not acceptable: a) User finds a file name for program using SFPutFile, for purposes of saving whatever your program saves. b) Program uses information in SFReply to fabricate a fully qualified pathname c) Program does "fopen(pathname,"w");" d) Macintosh knows of another online volume with the same name and with the same folder name as the one the user picked from SFPutFile. The pathname of this folder is identical to the pathname of the folder the User wishes to use to save his current work in, with one exception: It contains the only machine-readable copy of the User's PhD. thesis. By unlucky coincidence, the two base file names are identical. e) Macintosh says "I want the other disk." f) User inserts other disk, not suspecting for a moment that he is dealing with a dog-meat program. g) Current work is written over User's PhD. thesis. Screams are heard. A phone call is made to a powerful lawyer's office. h) "By mistake" you have destroyed a valuable document, and replaced it with something that was supposed to be placed elsewhere. Let us analyze the above scenario for a moment. The programmer has been too lazy to learn the correct way to access a file on the Macintosh. Instead, he has chosen to use a method that is suited to more to UNIX, VMS, and MS-DOS systems. Results were not as expected. The lazy programmer has made the Macintosh look bad, all because he failed to detect the difference between a Macintosh and another machine. I leave you with a question: Can you, members of the jury, think of this as an "honest mistake"? -- ********************************************************************* *Earle R. Horton, H.B. 8000, Dartmouth College, Hanover, NH 03755 * *********************************************************************
dwb@apple.UUCP (Dave W. Berry) (06/22/87)
In article <665@unicus.UUCP> rae@unicus.UUCP (Clith de T'nir a.k.a. Reid Ellis) writes: >Um, doesn't this ignore applications where a path is read from a text >file? [along the lines of a C compiler's "#include <a:long:path>"] What >then? Make the user memorize vRefNums of his folders? :-) Rather difficult, since vRefNums are dynamically assigned as directories get opened. And the correct thing to do is for the compiler to implement search paths so you don't have to give long full path names. What happens if you rename the disk, or copy the whole structure to hard disk? > > Reid -- David W. Berry dwb@well.uucp dwb@Delphi dwb@apple.com 293-0752@408.MaBell
rae@unicus.UUCP (Clith de T'nir a.k.a. Reid Ellis) (06/23/87)
In article <1127@apple.UUCP> dwb@apple.UUCP (David W. Berry) writes: |In article <665@unicus.UUCP> I write: |>Um, doesn't this ignore applications where a path is read from a text |>file? [along the lines of a C compiler's "#include <a:long:path>"] What |>then? Make the user memorize vRefNums of his folders? :-) | ... And the correct thing to do | is for the compiler to implement search paths so you don't | have to give long full path names. What happens if you | rename the disk, or copy the whole structure to hard disk? |-- | David W. Berry | dwb@well.uucp dwb@Delphi | dwb@apple.com 293-0752@408.MaBell I would agree that one should not *force* a user to use full pathnames, lest their fingers go numb :-), but what do you do when the user *does* type a long path? I wouldn't want to restrict her from doing so, so I must support it in my application. So my original point stands, What do you do to support long path names? Larry at Apple recently posted some code that helps with this, and it is muchly appreciated. Thanks Larry. Do you read Badger? Reid +=--
jimb@dopey.AMD.COM (Jim Budler) (06/25/87)
In article <6462@dartvax.UUCP) earleh@dartvax.UUCP (Earle R. Horton) writes:
)I agree! Byte the bullet, programmers! Use PBOpen, PBRead, PBWrite, and
)the entire ensemble of IN ROM Macintosh file handling routines to make
)your code more efficient and also more able to withstand the effects of
)system upgrades. You don't have to call SetVol(), you don't have to
It gives you something else, too. I wrote fpack for the Mac a year or so ago.
One condition that is very hard to detect with portable C is "DISK FULL"!
Corrupted output files galore...
How did I fix it? The very unelegant way of calling the ROM to find out how
much space I had left before I opened a file for writing, and keeping track
of how much I wrote. It worked, but I ain't proud of it.
fpack 3.x will come out one of these days, as will par/unpar. Both will use
the infinitely more responsive (i.e. PBWrite says "Disk Full", not "I just
wrote an 'a'") ROM IO calls.
By the way, it has come to my attention, through a friend, that fpack
is still circulating in the PD world, and that the copy he got (on his Jasmine)
didn't work. The copy on his Jasmine was version 2.0. I don't have the records
to show when the change came about, but version 2.2 is the earliest version
I can confirm was compiled with a version of Mac C which knows about HFS.
I believe the differences between 2.0, 2.1 and 2.2 are the compiler changes
and the version number resources.
Version 2.2 works on my Dataframe XP20.
Does anyone still care?
--
+ Jim Budler Advanced Micro Devices, Inc. (408) 749-5806 +
+ Compuserve: 72415,1200; Delphi: JIMBUDLER; Usenet: jimb@amdcad.AMD.COM +
dwb@apple.UUCP (Dave W. Berry) (06/30/87)
In article <684@unicus.UUCP> rae@unicus.UUCP (Clith de T'nir a.k.a. Reid Ellis) writes: >In article <1127@apple.UUCP> dwb@apple.UUCP (David W. Berry) (me!) writes: >|In article <665@unicus.UUCP> I write: >|>Um, doesn't this ignore applications where a path is read from a text >|>file? [along the lines of a C compiler's "#include <a:long:path>"] What >|>then? Make the user memorize vRefNums of his folders? :-) >| ... And the correct thing to do >| is for the compiler to implement search paths so you don't >| have to give long full path names. What happens if you >| rename the disk, or copy the whole structure to hard disk? >I would agree that one should not *force* a user to use full pathnames, >lest their fingers go numb :-), but what do you do when the user *does* >type a long path? I wouldn't want to restrict her from doing so, so I must >support it in my application. So my original point stands, What do you >do to support long path names? If you just pass the full path name to the open call you don't need to do anything special. -- David W. Berry dwb@well.uucp dwb@Delphi dwb@apple.com 293-0752@408.MaBell