[comp.unix.aux] A way to use UNIX programs on HFS files

tony@tui.marcam.dsir.govt.nz (Tony Cooper) (05/06/91)

UNIX programs under A/UX cannot use MacOS files stored on a HFS filesystem
because there is no UNIX driver for the HFS filesystem. But there is a simple
way to do this in a crude sort of way. Also this method has the possibilities
of allowing MacOS programs to use pipes (ie you can feed the output from a
MacOS program straight to the input of another MacOS program without creating
an intermediate file). The method uses a feature of UNIX that doesn't seem to
be widely known. So I thought that people would find it instructive (and
hopefully stimulating) if I showed how easy it is.

The method uses named pipes which can be created using the mknod command.
Suppose you create two called /dev/stdin and /dev/stdout. Then you can do
a unix command such as sort < /dev/stdin > /dev/stdout. Nothing happens
until some process send data to /dev/stdin and some process tries to read
from /dev/stdout. What you can then do is run a MacOS program to send data to
/dev/stdin and to read from /dev/stdout. Since it is a MacOS program it
can use files on the HFS filesystem. Thus you can sort a HFS file using
a UNIX sort program. With a little imagination and some MacOS programming
you can do far more sophisticated things. Also you can do things like
running BinHex on a MacOS file and sending the output to /dev/stdout (or
any named pipe) and run Unstuffit to unstuff the file /dev/stdout. That
way BinHex sends data to a pipe and Unstuffit reads from that pipe. That
could be quite nifty if it worked. (But the problem is that when BinHex
tries to send data to /dev/stdout it sees /dev/stdout as an existing file
and deletes it before making a new copy. This deletes the pipe which stops
the whole process from working).

Here is a simple demo of the process. I can't program under MacOS very well
so I've made the demo as simple as I can and just a stdin demo. Even so,
the MacOS program does not work properly. You have to run it from Commandshell
for it to work. Double clicking makes it crash.

Start by doing
/etc/mknod /dev/stdin p         (or make it /tmp/pipe or whatever).

Compile the MacOS program using the cc compiler or otherwise. Use the makefile
in /mac/src/examples to do see how to do this. Call the program MacStdin.

Make sure you are running Commandshell and type in 
cat < /dev/stdin > /tmp/myfile

From Commandshell run MacStdin. Choose a file using the file dialog. Hey
presto that MacOS file will be operated on by the UNIX cat command.

I hope the process is understandable from this brief posting. I hope it
inspires someone to write a more useful MacOS utility to do it in general.
I can help with the UNIX side of things if you like.

Cheers
Tony Cooper
sramtrc@albert.dsir.govt.nz

Here's the MacOS program to read a HFS file and send it to /dev/stdin.

#include <mac/types.h>
#include <mac/packages.h>
#include <mac/quickdraw.h>
#include <mac/osutils.h>
#include <mac/files.h>
#include <mac/errors.h>
#include <mac/strings.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <strings.h>
#include <fcntl.h>
#include <stdio.h>

main()
{
	Point		where;
	short		refNum, numTypes;
	SFReply		reply;
	SFTypeList	typeList;
	char		*prompt = "";
	OSErr		err;
	char		buffer[512];
	long		bufSize;
	void		MultiFinder();
	int		fd;

	MultiFinder(20);	/* initialise the MacOS stuff */

	where.h = 50;
	where.v = 50;
	numTypes = -1;

	sfgetfile(where, prompt, nil, numTypes, typeList, nil, &reply);
	if(!reply.good) ExitToShell();

	fd = open("/dev/stdin", O_GLOBAL|O_WRONLY);
	if (fd > 0) {
	    if ((err = FSOpen(reply.fName, reply.vRefNum, &refNum)) == noErr) {
		do {
			bufSize = 512;
			(void)FSRead(refNum, &bufSize, buffer);
			(void)write(fd, buffer, bufSize);
		} while (bufSize > 0);
		(void)FSClose(refNum);
		(void)close(fd);
	    }
	}
	ExitToShell();
}

void MultiFinder(sleep)
short sleep;
{
    EventRecord theEvent;
    static int firstTime = 1;

    if (firstTime == 1) {	/* initialize everything */
	InitGraf(&qd.thePort);
	InitWindows();
	InitFonts();
        InitMenus();
        InitDialogs(nil);
	InitCursor();
	FlushEvents(everyEvent, 0);
	firstTime = 0;
    }
    (void) WaitNextEvent(everyEvent, &theEvent, sleep, 0);
}

Here is the MacStdin.r file:

#include "types.r"

resource 'SIZE' (-1,"Size Resource") {
	dontSaveScreen,
	ignoreSuspendResumeEvents,
	enableOptionSwitch,
	cannotBackground,
	notMultiFinderAware,
	backgroundAndForeground,
	dontGetFrontClicks,
	ignoreChildDiedEvents,
	is32BitCompatible,
	reserved,
	reserved,
	reserved,
	reserved,
	reserved,
	reserved,
	reserved,
	64*1024,			/* preferred memory size */
	64*1024				/* minimum memory  size */
};