[comp.sys.amiga.tech] Anybody know how to do this stuff?

koren@hpfelg.HP.COM (Steve Koren) (11/29/89)

I have a few how-to-do-it style questions for knowlegable Amiga people.
Probably email is best for responses; I'll summarize and post if there
is sufficient interest.

1) How do you move bits around the filesystem as fast as possible?  I
   am looking to improve the performance of the 'cp' command in SKsh.
   Right now, I have a loop that does a read() and a write() in 32K
   chunks (I've tried everything from 4K to 32K).  However, c:copy still
   has a large performance advantage (for the FFS on a 28ms drive).

2) There's a command called something like "SetWindowTitles()" (I'm
   doing this from memory so that may not be the exact name).  I can
   set the window title to anything I choose; I've found from experimentation
   that I need to AllocMem() the memory for the title so that it doesn't
   go away when my program terminates (since apparently SetWindowTitles()
   doesn't copy the string you give it, it just uses it directly).  Well,
   that much is no problem.  But I'd like to get rid of the space used by
   the *old* title.  I am afraid to just FreeMem() it, though, since my
   program hasn't a clue where it came from.  It *could* have been created
   by an AllocMem() call, or it could be a static string in some program.
   In the latter case, it would be quite rude to FreeMem() the string.
   How do I get rid of it if I don't know where it came from? (I can't
   just save it and put it back later since I am creating a stand-alone
   binary which changes the title).  Also, if I assume it was AllocMem()ed,
   I don't know how big the buffer was.  For example, it could have been
   100 allocated bytes with a 20 byte string copied into it.  Since
   FreeMem() needs to know the byte size, I wouldn't be freeing all the
   memory.
   
3) How do you execute a program when you know it is resident?  I can
   get a pointer to a resident structure if I have the name; that's no
   problem.  But I'm not sure what to do from there.  I can't find a
   seglist in the structure anywhere.  (Even if I had one, there's still
   the problem of BCPL programs being different thaan Lattice programs
   which are different from Manx programs which are different from
   programs compiled on Tuesday).  Also, is the ARP resident list the
   same thing as the AmigaDos resident list?  Does anyone have a
   short bit of code they'd be willing to pass along which executes
   resident programs?  Even if I don't use it directly at least I could
   perhaps check it out to see how to do it.


   Any help would be greatly appreciated,

     thanks,

       - steve (koren@hpfela.HP.COM)

jimm@amiga.UUCP (Jim Mackraz) (12/01/89)

In article <13920020@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
)2) There's a command called something like "SetWindowTitles()" (I'm
)   doing this from memory so that may not be the exact name).  I can
)   set the window title to anything I choose; I've found from experimentation
)   that I need to AllocMem() the memory for the title so that it doesn't
)   go away when my program terminates (since apparently SetWindowTitles()
)   doesn't copy the string you give it, it just uses it directly).  Well,
)   that much is no problem.  But I'd like to get rid of the space used by
)   the *old* title.  I am afraid to just FreeMem() it, though, since my
)   program hasn't a clue where it came from.  It *could* have been created
)   by an AllocMem() call, or it could be a static string in some program.
)   In the latter case, it would be quite rude to FreeMem() the string.
)   How do I get rid of it if I don't know where it came from? (I can't
)   just save it and put it back later since I am creating a stand-alone
)   binary which changes the title).  Also, if I assume it was AllocMem()ed,
)   I don't know how big the buffer was.  For example, it could have been
)   100 allocated bytes with a 20 byte string copied into it.  Since
)   FreeMem() needs to know the byte size, I wouldn't be freeing all the
)   memory.

In normal circumstances, this is no problem.  If you close your window
when you exit, Intuition will not need to fetch that window's screen title
again, I believe.  It leaves it rendered on the screen bar, and
hangs onto the pointer, but that pointer gets reset when any window
becomes active in the same screen.  I'm pretty sure that the title
won't get rerendered using the bogus pointer.

Do you have a counterexample?  It sounds a lot like you are setting
titles for windows you do not own and then exiting, or otherwise
treading dangerously on thin ice.

You should try not to leave little "title turds" hanging around in memory,
nor should you guess whether to free memory you encounter.

Write a library, have it track your memory turds, and when you call
its SetAllocedWindowTitles(), it will toss the old title if it recognizes
as something from its list.  You could also hang a bookkeeping list
off of a named port that your weird little program can find.

    jimm

-- 
--------------------------------------------------	- opinions by me
"This voice console is a *must*.  I press Execute. 
 `Hello, I know that you've been feeling tired.
  I bring you love and deeper understanding.' "		-lyrics by Kate Bush

koren@hpfelg.HP.COM (Steve Koren) (12/04/89)

> Do you have a counterexample?  It sounds a lot like you are setting
> titles for windows you do not own and then exiting, or otherwise
> treading dangerously on thin ice.

Well, this point is a little unclear to me.  Who "owns" the CLI window?
Is the the currently running shell?  What if a shell is invoked from
within a shell?  I wished to add a command which lets the user change
the window title bar of the CLI window by saying something like:

     window -title "my title"

I wanted to implement this command as an external binary.  The binary
sets the window title and then exits.  Perhaps that is not a legal thing
to do, in which case I'll leave the command out.

It is probably a bit late for this now, but it is my belief (just opinion
here) that a child procedure should not depend on dynamically allocated data
passed to it hanging around after the child exits.  If it needs the data,
it should copy it.  Having it depend on the data's persistance increases
coupling strength between the two procedures, which is generally regarded
as a "bad thing" in software engineering circles.  (Of course, I do this
sometimes myself :-)

Anyhow, thanks for the help.

    - steve

koren@hpfelg.HP.COM (Steve Koren) (12/07/89)

Another "how do you do it" question:

I want to find out, for any given device name, whether that is a currently
mounted file system device.  Moreover, I want to do this without bringing
up the requester.  In short, I need a routine like this:

   int IsMounted(char *Device_Name) {}

First of all, I would expect that there would be an easy way to do it;
ie, something like the above function call.  If there is no programatic
interface to this, I will probably forget it until one appears.  Does
anyone know?  I can't find it documented anyplace, but it seems like a
logical thing to have.  (On the other hand, a way to execute programs
seems like a logical thing to have, too, and that's not there either, at
least not in a usable manner).

I tried to write such a function using ARP's AddDADevs() call, but I had
problems with that.  They have a flag called DLX_UNMOUNTED which you can
examine, but it is only valid for "volume" names, not device (like df0:)
or "dir names" (like c:).  It tells me that df0: is always mounted, even if
it contains no disk, and it tells me that c: is never mounted, even though
it is assigned someplace.  In short, it doesn't do me any good.

Anybody know if my IsMounted() funtion exists, or if not, when it might
appear?

       - steve

peter@sugar.hackercorp.com (Peter da Silva) (12/08/89)

In article <13920023@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
> Well, this point is a little unclear to me.  Who "owns" the CLI window?

Its instance of console.device.

The *best* situation would be a console.device that took escape sequences
for "set window title", "set menu", and so on.
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U` "Really, a video game is nothing more than a Skinner box."
       -- Peter Merel <pete@basser.oz>

jms@tardis.Tymnet.COM (Joe Smith) (12/09/89)

In article <13920023@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
Steve> Well, this point is a little unclear to me.  Who "owns" the CLI window?

In article <4698@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes:
Peter>Its instance of console.device.
Peter>The *best* situation would be a console.device that took escape sequences
Peter>for "set window title", "set menu", and so on.

I second that suggestion.  Something like:

ESC ] l title-for-window ESC \	To change the title on an open window
ESC [ 2 t			To iconify the window
ESC ] L label ESC \		To change label of iconified window
ESC ] I DH0:file.info ESC \	To use different icon image
ESC [ 1 t			To go from icon back to normal window
ESC [ 3 ; 5 0 ; 1 0 0 t		To move upper left corner to y=50, x=100
ESC [ 4 ; 2 0 0 ; 6 4 0 t	To make window full size (200x640 pixels)
ESC [ 5 t			Window to front
ESC [ 6 t			Window to back
ESC [ 7 t			Redraw window
ESC [ 8 ; 1 2 ; 4 0 t		Change size to 12 rows of 40 columns

Does any system other than Sun use these escape sequences?
Has anyone hacked up a console.device to use something like this?
-- 
Joe Smith (408)922-6220 | SMTP: JMS@F74.TYMNET.COM or jms@gemini.tymnet.com
BT Tymnet Tech Services | UUCP: ...!{ames,pyramid}!oliveb!tymix!tardis!jms
PO Box 49019, MS-D21    | PDP-10 support: My car's license plate is "POPJ P,"
San Jose, CA 95161-9019 | humorous dislaimer: "My Amiga speaks for me."

ecarroll@vax1.tcd.ie (Eddy Carroll) (12/10/89)

In article <13920027@hpfelg.HP.COM>, koren@hpfelg.HP.COM (Steve Koren) writes:
> Another "how do you do it" question:
> 
> I want to find out, for any given device name, whether that is a currently
> mounted file system device.  Moreover, I want to do this without bringing
> up the requester.  In short, I need a routine like this:
> 
>    int IsMounted(char *Device_Name) {}
> 

The following seems to do the trick:

/* Compile with Lattice C V5.04 */

#include <exec/types.h>
#include <proto/exec.h>
#include <proto/dos.h>

/*
 *  Checks to see if the specified device (DF0:, DF1:, XYZ: etc.) is
 *  mounted; returns TRUE if it is, FALSE if it isn't.
 */
int IsMounted(devname)
char *devname;
{
    BPTR lock;
    APTR oldwindow;
    struct Process *me = (struct Process *)FindTask(NULL);

    oldwindow = me->pr_WindowPtr;       /* Save current requester state */
    me->pr_WindowPtr = (APTR)-1;        /* Disable AmigaDOS requesters  */
    lock = Lock(devname, ACCESS_READ);  /* Try and get lock on device   */
    if (lock)                           /* If we succeeded,             */
        UnLock(lock);                   /*     Free up the lock         */
    me->pr_WindowPtr = oldwindow;       /* Restore original requesters  */
    return (lock);                      /* Return TRUE if device online */
}

>        - steve
I'm really impressed with SKsh. As many others have said already, a "real"
Unix shell has long been overdue for the Amiga (though Matt's shell has done
me nicely in the meantime).
-- 
Eddy Carroll             ----* Genuine MUD Wizard  | "You haven't lived until
INTER: ecarroll@vax1.tcd.ie                        |    you've died in MUD!"
 UUCP: {..uunet}!mcvax!ukc!vax1.tcd.ie!ecarroll    |  -- Richard Bartle

peter@sugar.hackercorp.com (Peter da Silva) (12/11/89)

In article <13920027@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
> I want to find out, for any given device name, whether that is a currently
> mounted file system device.

There are two parts to this question. First, whether it's a file-system device.
Second, whether it's currently mounted. The second is easy... you can just
set your pr_windowptr to -1 and try to access it. To see if it's a file
system device is a bit harder. You can try doing a getdiskinfo on it.

Or you can traverse the device list and kill two birds with one stone. Let
me dig up the code...

Bummer. That disk has an error. I'll run disksalv on it while I read news and
let you know what comes out. (let's see you do *that* on a Mac!)
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U`  "I haven't lost my mind, it's backed up on tape somewhere"

peter@sugar.hackercorp.com (Peter da Silva) (12/11/89)

Here it is, as promised. You can scan the device list with this code, and do
all sorts of fun stuff. Make SKSH the first program to support wildcarding
the device name!

: This archive contains the following files...
: 'mounted.c'
: 'readme'
: To extract them, run the following through /bin/sh
echo x - mounted.c
sed 's/^X//' > mounted.c << '//END'
X/* MOUNTED -- is a disk mounted?
X *
X * Copyright 1987 by Peter da Silva.
X *
X * This code may be freely distributed provided this notice is
X * retained. It may be hacked, munged, and incorporated in commercial
X * software if you want, so long as you credit me for it.
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <libraries/dosextens.h>
X
Xstruct DosLibrary *DosLibrary;
X
X/* hack BPTRS */
X
X#define toAPTR(b) ((b)<<2)
X#define toBPTR(a) ((a)>>2)
X
X#define VOLUMES 16 /* If you have more than 16 drives, tough luck :-> */
Xchar volumes[VOLUMES][33];
Xint nvols;
X
Xmain(ac, av)
Xint ac;
Xchar **av;
X{
X	GetVolumes();
X	if(ac==0) wbmain(); /* I think this should work with Lattice */
X	else if(ac==1) dumpvols();
X	else if(ac==2 && av[1][0] != '?')
X		exit(mounted(av[1])?0:5); /* Code 5 is warn */
X	else {
X		/* should loop & return success only if all work. */
X		printf("MOUNTED Copyright (c) 1987 by Peter da Silva.\n");
X		printf("Usage: mounted [volumename]\n");
X		printf("Returns error code 5 is volume is not mounted.\n");
X		exit(10); /* code 10 is error. maybe Should be 20 (fatal). */
X	}
X	exit(0);
X}
X
XGetVolumes() /* who'se out there */
X{
X	struct RootNode *root;
X	struct DosInfo *info;
X	struct DeviceList *list;
X
X	DosLibrary = OpenLibrary("dos.library", 0);
X	if(!DosLibrary) {
X		printf("Can't open dos.library\n");
X		exit(2);
X	}
X	nvols = 0;
X
X	/* The following 3 lines caused me some worry, but they worked
X	   first time. Thank you C=Amiga. */
X	root = DosLibrary -> dl_Root;
X	info = toAPTR(root->rn_Info);
X	list = toAPTR(info->di_DevInfo);
X	while(list) {
X		if(list->dl_Type == DLT_VOLUME && /* is it a device? */
X		   list->dl_Task != 0) { /* Ignore unmounted devices */
X			char *ptr;
X			int count;
X			ptr = toAPTR((BPTR)list->dl_Name);
X			count = *ptr++;
X			if(count > 16) /* Should be a CONSTANT */
X				count = 16;
X			strncpy(volumes[nvols], ptr, count);
X			volumes[nvols][count] = 0;
X			nvols++;
X		}
X		list = toAPTR(list->dl_Next);
X	}
X	CloseLibrary(DosLibrary);
X}
X
Xwbmain(dummy) /* if run from workbench, just list mounted volumes */
X{
X	FILE *fp;
X	if(!(fp = fopen("CON:160/50/320/100/Mounted volumes.")))
X		return;
X	fdumpvols(fp);
X	sleep(10);
X	fclose(fp);
X}
X
Xsleep(n) /* This should have been provided by Aztec, for god's sake. */
X{
X	Delay(50*n);
X}
X
Xdumpvols()
X{
X	fdumpvols(stdout);
X}
X
Xfdumpvols(fp)
XFILE *fp;
X{
X	int i;
X	for(i = 0; i < nvols; i++)
X		printf("%s\n", volumes[i]);
X}
X
Xmounted(name) /* The biggee */
Xchar *name;
X{
X	int i;
X	for(i = 0; i < nvols; i++)
X		if(streq(volumes[i], name))
X			return 1;
X	return 0;
X}
X
Xstreq(s1, s2)
Xchar *s1, *s2;
X{
X	normalise(s1);
X	normalise(s2);
X	return strcmp(s1, s2)==0;
X}
X
Xnormalise(s)
Xchar *s;
X{
X	int i;
X	for(i = 0; s[i]; i++)
X		if(isupper(s[i]))
X			s[i] = tolower(s[i]);
X		else if(s[i]==':') {
X			s[i] = 0;
X			break;
X		}
X}
//END
echo x - readme
sed 's/^X//' > readme << '//END'
XMOUNTED is a quick little program I wrote to tell if a disk is mounted
Xor not. It's intended to be used in startup-sequences to conditionally
Xexecute programs from df1. For example, mine includes:
X
Xmounted playit
Xif not warn
X    run playit:play playit:bachfugue.smus playit:
Xendif
X
XSo if I start up with the disk "playit" in df1: it plays a bach fugue
Xduring loading. This program illustrates how to deal with BPTRs in a
Xwell behaved way, and how to get hold of the device list. It's full
Xof magic numbers and inefficient code, and including stdio bloats it
Xup to 8K. A little tidying up can probably get it down quite a bit. But
Xit fits nicely in *my* c: directory and I'm arrogant enough to think
XI have better things to do. It's a good idea to have the AmigaDOS
Xmanual open to pages 266-269 while you're checking out the code.
XIt's written for Aztec V3.40a with the +P option set, so it should run 
Xjust fine with Lattice.
X
X		-- Peter da Silva.
X		-- Author of the fantastic screen hack "Workbench Lander".
X		-- And incredibly modest guy.
//END
: end of archive.
exit 0
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U`  "I haven't lost my mind, it's backed up on tape somewhere"

cmcmanis%pepper@Sun.COM (Chuck McManis) (12/11/89)

In article <13920027@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
>Another "how do you do it" question:
>
>I want to find out, for any given device name, whether that is a currently
>mounted file system device.  Moreover, I want to do this without bringing
>up the requester.  In short, I need a routine like this:
>
>   int IsMounted(char *Device_Name) {}

The simple way :
	#include <libraries/dosextens.h>

	APTR	OldWindow;
	ULONG	l, mounted;
	struct Process	*pr;

	OldWindow = pr->pr_WindowPtr;
	pr->pr_WindowPtr = -1;		/* Turn off requesters */
	l = Lock(Volume_Name, ACCESS_READ); /* Check for volume mounted */
	mounted = (l != 0);
	if (mounted)
		UnLock(l);
	pr->pr_WindowPtr = OldWindow;
	return(mounted);

>First of all, I would expect that there would be an easy way to do it;
>ie, something like the above function call.  If there is no programatic
>interface to this, I will probably forget it until one appears.  Does
>anyone know?  I can't find it documented anyplace, but it seems like a
>logical thing to have.  

The above code will do what you want, however ...

>I tried to write such a function using ARP's AddDADevs() call, but I had
>problems with that.  They have a flag called DLX_UNMOUNTED which you can
>examine, but it is only valid for "volume" names, not device (like df0:)
>or "dir names" (like c:).  It tells me that df0: is always mounted, even if
>it contains no disk, and it tells me that c: is never mounted, even though
>it is assigned someplace.  In short, it doesn't do me any good.

You don't seem to grok what Volume's are. They are basic unit of Disk, not
the device like df0:. If I have a volume on a floppy, I don't care what 
disk drive it is in. DF0: is a device which is either present or not 
present. That and the geometry of the disks it will read aree the only
interesting tidbits about it. You can figure out if a volume is currently
inserted into DF0: but generally this is useless info. Assigns, like C:,
are something else entirely. Their function is to name a file or directory
unambiguously. They provide a "universal" name for different directories.
The information provided within the assignment includes the volume that
they point are actually on so it is fairly trivial to check to see if
they are available. But again, they are never "mounted", they simply
exist to say "If you need this named group of files, this context
independent name will point to them." 


Is that any clearer?

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@Eng.Sun.COM
These opinions are my own and no one elses, but you knew that didn't you.
"If it didn't have bones in it, it wouldn't be crunchy now would it?!"

koren@hpfelg.HP.COM (Steve Koren) (12/11/89)

>    int IsMounted(char *Device_Name) {}

Ok, I have the solution now.  Thank you to those who responded.  The
solution was only a few lines of code; you have to make the pointer to
the error window (-1), call Lock(), then restore the pointer.

      - steve

fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (12/12/89)

     If I followed this discussion correctly the fundamental question is
how do you find out what disk devices are configured?  That's important if
you want to write a file requester that automatically creates a button for
each disk device.  How do I know the system has df0:?  Oh, right, they all
have df0:.  Well, what about df3:?  Is there a RAM: drive?  A RAD:?

--Fabbian Dufoe
  350 Ling-A-Mor Terrace South
  St. Petersburg, Florida  33705
  813-823-2350

UUCP: ...uunet!pdn!jc3b21!fgd3

kodiak@amiga.UUCP (Robert R. Burns) (12/13/89)

In article <4731@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes:
)Here it is, as promised. You can scan the device list with this code, and do
)all sorts of fun stuff.
)X/* MOUNTED -- is a disk mounted?
)X *
)X * Copyright 1987 by Peter da Silva.
)X *
)X * This code may be freely distributed provided this notice is
)X * retained. It may be hacked, munged, and incorporated in commercial
)X * software if you want, so long as you credit me for it.

Please hack it to include a Forbid() around the manipulation of the dos
device list, lest you find yourself holding onto an obsolete node and then
linking off to junk.
-- 
Bob Burns, amiga!kodiak						 _
	| /_  _|. _ |		   Commodore __			|_) _ |_  _ )'
	|<(_)(_)|(_\|<		    /\ |  ||| _` /\		|_)(_\| )(_\ |
	| \ Software		___/..\|\/|||__|/..\___			 Faith

doug@xdos.UUCP (Doug Merritt) (12/13/89)

In article <4731@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes:
>Here it is, as promised. You can scan the device list with this code, and do
>all sorts of fun stuff. Make SKSH the first program to support wildcarding
>the device name!

Hey! My "filetype" program was the first to support wildcards in device
names!

I claim priority by about 2 1/2 years.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

doug@xdos.UUCP (Doug Merritt) (12/13/89)

In article <4730@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes:
>In article <13920027@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
>> I want to find out, for any given device name, whether that is a currently
>> mounted file system device.
>
>There are two parts to this question. First, whether it's a file-system device.
>Second, whether it's currently mounted. The second is easy... you can just
>set your pr_windowptr to -1 and try to access it. To see if it's a file
>system device is a bit harder. You can try doing a getdiskinfo on it.
>
>Or you can traverse the device list and kill two birds with one stone. Let
>me dig up the code...
>
>Bummer. That disk has an error. I'll run disksalv on it while I read news and
>let you know what comes out. (let's see you do *that* on a Mac!)

Since I haven't seen Peter's code yet (DOA? Give my regards to Lazarus),
here's mine ("fs.c").

Hmmm. I just saw Peter's code after all, but since I spent an
hour creating "fs.c" out of the relevent piece of my "filetype" program,
I'll post it anyway. It does lots more than Peter's code (weak justification
for posting :-).

In fact, it does more than you asked for...given a device/volume/assign
name, it tells you everything known about it (see examples below).

If you want to follow Peter's suggestion about having SKsh wildcard
device names, I'm very much in favor...I'm always wishing the CLI
supported that. Anyway, as I said in another posting today, my filetype
program does exactly that, and I can give you complete working code
to support that feature if you want it.

As for this "fs.c", it works quite well, although I see Chuck McManis
just posted something (Subject: "Re: Problem with handler) that suggests
that in addition to checking for a handler task, I should perhaps also
check DSKENV and even send an ACTION_DISKINFO packet. I'll have to look
into that; but meanwhile the simple check has never produced any problem
reports.

Examples of 'fs' in action:

For instance, "fs Workbench1.3:" produces
	Workbench1.3: -- volume (mounted on DF0)

Conversely, "fs df0:" produces
	df0: -- device (file system; contains Workbench1.3)

After ejecting the diskette, the same commands produces
	df0: -- device (file system; ejected)

Or for ASSIGN'ed directories, "fs src:" produces
	src: -- directory (SupraDrive0:SOURCE)

The code works on ram:, rad:, etc. Hope it helps.
	Doug
--
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary
---------------------- CUT HERE ----------------------------------
/*
 * fs -- check filesystem devices (extracted from my 'filetype' source)
 *
 * copyright 1987 Douglas R. Merritt
 * License to use is hereby granted on the condition that this
 * notice be retained unchanged, and that any commercial
 * use must conspicuously credit the copyright holder.
 *
 */
#define	NONE_SUCH	0
#define	DEVICE		1
#define	DIRECTORY	2
#define	VOLUME		3

char	*ExtraInfo;

#define	TextCountDirEntries(N)	""

char	*strdup(), *Name2Path(), *concat3();

#include	"ctype.h"
#include	"exec/types.h"
#include	"libraries/dos.h"

#ifdef BADDR
#undef BADDR
#endif
#define BADDR(N)	((char *) ( ((ULONG)(N)) << 2) )

#define BCAST(TYPE, VAL)	((TYPE) BADDR((ULONG)VAL))

/*
 * RoundUp0 -- ceiling (yields 0 if n % TO == 0)
 * BufRound -- given buffer address, rounds up to word boundary
 */
#define RoundUp0(N,TO)      ( (TO - (((ULONG)N) & (TO-1)) ) & (TO-1))
#define BufRound(BUF)       &BUF[ RoundUp0(BUF,4) ]

extern  char *calloc();
extern  struct FileHandle *Output(), *Open(), *output;
extern  ULONG Read();

#include	"exec/nodes.h"
#include	"exec/memory.h"
#include	"exec/resident.h"
#include	"libraries/dosextens.h"
#include	"libraries/dos.h"
#include	"libraries/diskfont.h"
#include	"libraries/filehandler.h"
#include	"exec/libraries.h"
#include	"workbench/startup.h"

ULONG   Examine(), ExNext();	/* move to def.h? */
struct  FileLock *Lock(), *ParentDir();
struct	Process *FindTask();

struct	FileInfoBlock *GetInfo();
char	*FileName(), *Name2Path(), *concat3();

extern  struct DosLibrary *DOSBase;
typedef struct DeviceList *DevPtr;

/************************* misc. functions ************************/
/*
 * is this a device name? (e.g. "ser:")
 */
int
IsDevName(name)
	char	*name;
{
	char	*s;

	for (s=name; *s; ++s)
		if (*s == ':') break;
	if (!s[0] || s[1]) return(0);
	return(1);
} /* IsDevName() */

/*
 * compare a string and a BSTR, case-insensitive
 */
StrBstrCmp(s, b)
	unsigned char *s;
	BPTR  b;
{
	int	total, rdone, sdone, c1, c2;
	unsigned char *r, *rstart;

	if (!s || !b) return(-1);
	r = (unsigned char *) BADDR(b);
	total = *r++;
	rstart = r;
	rdone = sdone = 0;
	while (1) {
		if (!*s) sdone = 1;
		if ((r - rstart) >= total) rdone = 1;
		if (sdone || rdone)
			return(sdone - rdone);
		c1 = isupper(*s) ? tolower(*s) : *s;
		c2 = isupper(*r) ? tolower(*r) : *r;
		if (c1 != c2) return(c1 - c2);
		++s; ++r;
	}
	/*NOTREACHED*/
} /* StrBstrCmp() */

/*
 * convert a BSTR to a string
 *      We count on exit() freeing the allocated memory.
 */
char *
Bstr2Str(s)
	unsigned char    *s;
{
	char    *ret;
	int	len;

	if (!s)	s = (unsigned char *) "\0";
	else	s = (unsigned char *) BADDR(s);
	len = s[0] & 0xff;
	ret = calloc(1, len+2);
	strncpy(ret, &s[1], len);
	ret[ len ] = '\0';
	return(ret);
} /* Bstr2Str() */

/*
 * given a pointer to the MsgPort part of a task structure, return
 *      the name found in the Node portion.
 */
char *
taskname(p)
	struct  MsgPort *p;
{
	struct  Node *t;
		char    *s;

	if (!p) return(0);
	t = (struct Node *) p->mp_SigTask;
	if (t->ln_Name) {
		s = t->ln_Name;
		if (*s)
			return(strdup(s));
	}
	return((char *) 0);
} /* taskname() */

/*
 * case-insensitive string compare
 */
stricmp(a, b)
	/*register*/ char    *a, *b;
{
	int	     c1, c2;

	if (!a || !b) return(-1);
	while (*a && *b) {
		c1 = isupper(*a) ? tolower(*a) : *a;
		c2 = isupper(*b) ? tolower(*b) : *b;
		if (c1 != c2) return(c1 - c2);
		++a; ++b;
	}
	return(((int) *a) - ((int) *b));
} /* stricmp() */

#define GetLock(cur)    BCAST(struct FileLock *, cur->dl_Lock)
#define GetVol(cur)     BCAST(struct DeviceList *, cur->fl_Volume)
#define DevNode(cur)    ((struct DeviceNode *) cur)
#define IsVolMounted(cur)   (cur->dl_Task != NULL)

/*
 * Find device list entry of specified type and handler values.
 *	Used to match volumes with devices & vice versa.
 */
struct	DeviceList *
FindDevType(task, type)
	struct	MsgPort	*task;
	ULONG		type;
{
	struct  DosInfo		*dos;
	struct  RootNode	*root;
	struct	DeviceList 	*dev, *cur;

	if (!task) return(0);
	/*
	 * find device list, starting from Dosbase; see AmyDos Tech. Ref Man
	 *      and libraries/dosextens.h
	 */
	root = (struct RootNode *) DOSBase->dl_Root;
	dos = BCAST(struct DosInfo *,    root->rn_Info);
	dev = BCAST(struct DeviceList *, dos->di_DevInfo);

	/* device is *supposed* to be treated differently, so we do: */
	if (type == DLT_DEVICE) {
		Forbid();
		for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) {
			if (cur->dl_Type != DLT_DEVICE)
				continue;
			if (DevNode(cur)->dn_Task == task) {
				Permit();
				return(cur);
			}
		}
		Permit();
	} else {
		Forbid();
		for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) {
			if (cur->dl_Type != type)
				continue;
			if (cur->dl_Task == task) {
				Permit();
				return(cur);
			}
		}
		Permit();
	}
	return(0);
} /* FindDevType() */

/*
 * check device list to see if this name is on it
 */
int
IsDevice(buf)
	char    *buf;
{
	struct  DosInfo		*dos;
	struct  RootNode	*root;
	struct	MsgPort		*task;
	DevPtr  dev, cur;
	char    *s, name[128], *strchr();
	char	*str, *on, *devname;
	enum	FILETYPE ret;
	int	mtd, isfs;
	struct	Process *tp;
	APTR	tmp;


	strcpy(name, buf);
	if (s=strchr(name, ':')) *s = '\0';	/* erase ':' */
	else return(NONE_SUCH);	/* fail safe...shouldn't happen */
	/*
	 * find device list, starting from Dosbase; see AmyDos Tech. Ref Man
	 *      and libraries/dosextens.h
	 */

	Forbid(); /* vvvvvv */

	root = (struct RootNode *) DOSBase->dl_Root;
	dos = BCAST(struct DosInfo *,    root->rn_Info);
	dev = BCAST(struct DeviceList *, dos->di_DevInfo);
	for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) {
		s = BCAST(char *, cur->dl_Name);
		if (StrBstrCmp(name, cur->dl_Name)) continue;
		switch(cur->dl_Type) {
		case DLT_DEVICE:
#if 0
/*
 * this older code is interesting, but it turns out nobody puts
 * anything very useful in those fields.
 */
			if (DevNode(cur)->dn_Handler) {	
				ExtraInfo =
					Bstr2Str(DevNode(cur)->dn_Handler);
			} else if (DevNode(cur)->dn_Task) {
				ExtraInfo = taskname(DevNode(cur)->dn_Task);
			}
			if (!ExtraInfo || !*ExtraInfo ||
			    !isprint(*ExtraInfo) || !isprint(ExtraInfo[1]))
				ExtraInfo = "no id";
#endif
			task = DevNode(cur)->dn_Task;

			Permit();  /* ^^^^^^ */

#if 0
			tp = FindTask((char *) 0 );
			tmp = tp->pr_WindowPtr;
			tp->pr_WindowPtr = (APTR) -1L;
			isfs = IsDir(GetInfo(buf));
			tp->pr_WindowPtr = tmp;
			if (isfs) {
#endif
			if (task) {
				char	buf[256], *str;

				strcpy(buf, "file system; ");
				if (cur=FindDevType(task, DLT_VOLUME)) {
					str = Bstr2Str(cur->dl_Name);
					strcat(buf, "contains ");
					strcat(buf, str);
					free(str);
				} else {
					strcat(buf, "ejected");
				}
				ExtraInfo = strdup(buf);
			} else {
				ExtraInfo = "non-file system";
			}
			return(DEVICE);
		case DLT_DIRECTORY:
			cur = GetVol(GetLock(cur));
			mtd = IsVolMounted(cur);

			Permit();	/* ^^^^^^ */

			if (mtd) {
				ExtraInfo = Name2Path(buf);
			} else {
				char	*tmp, *dup;

				dup = Bstr2Str(cur->dl_Name);
				tmp = "unmounted volume ";
				ExtraInfo = concat3(tmp, dup, "");
				free(dup);
			}
			return(DIRECTORY);
		case DLT_VOLUME:
			mtd = IsVolMounted(cur);

			Permit();	/* ^^^^^^ */

			if (!mtd) {
				ExtraInfo = "unmounted";
				return(VOLUME);
			}
			/*
			 * avoid bug in ram disk; try
			 *	dir "RAM Disk:"
			 * (task hangs, don't say I didn't warn you)
			 */
			if (!stricmp(buf, "RAM Disk:")) {
				str = TextCountDirEntries("ram:");
			} else {
				str = TextCountDirEntries(buf);
			}
			task = DevNode(cur)->dn_Task;

			/* "impossible" error: */
			if (!(cur=FindDevType(task, DLT_DEVICE))) {
				devname = strdup("???");
			} else {
				devname = Bstr2Str(cur->dl_Name);
			}
			on = "mounted on ",
			ExtraInfo = concat3(str, on, devname);
			free(str);
			free(devname);
			return(VOLUME);
		default:
			Permit();	/* ^^^^^^ */

			ret = NONE_SUCH;
			return(ret);
		}
		break;
	}
	Permit();	/* ^^^^^^ */
	return(NONE_SUCH);	/* unknown volume name */
} /* IsDevice() */

/*
 * copy a string into newly allocated space
 */
char *
strdup(s)
	char	*s;
{
	char	*ret;

	if (!s) return(0);
	ret = calloc(1, strlen(s)+1);
	strcpy(ret, s);
	return(ret);
} /* strdup() */

/*
 * concatenate 3 strings into newly allocated storage
 */
char *
concat3(a, b, c)
	char	*a, *b, *c;
{
	int	total;
	char	*ret;
	register char *tmp;

	total = strlen(a) + strlen(b) + strlen(c);
	tmp = ret = calloc(1, total+1);
	while (*a)
		*tmp++ = *a++;
	while (*b)
		*tmp++ = *b++;
	while (*c)
		*tmp++ = *c++;
	*tmp = '\0';
	return(ret);
} /* concat3() */

/*
 * convert any name (e.g. relative to current directory) to its
 *	true full path name (in newly allocated space)
 */
char *
Name2Path(name)
	char	*name;
{
	struct  FileLock *Ilock;
	char	buf[256];

	Ilock = Lock(name, (ULONG) ACCESS_READ);
	if (!Ilock) return(strdup(name));
	Lock2Path(Ilock, buf);
	UnLock(Ilock);
	return(strdup(buf));
} /* Name2Path() */

/*
 * Get full path corresponding to lock (locked file should exist!)
 *	Since we have to go upward one directory at a time,
 *	we have to go all the way to the top before we can build
 *	the path left to right. A data stack is used for this.
 */
Lock2Path(curlock, pathbuf)
	struct	FileLock	*curlock;
	char	*pathbuf;
{
#define	LOCKSTACKSIZE	128
	struct	FileLock *locklist[LOCKSTACKSIZE];
	UBYTE    Ibuf [ sizeof(struct FileInfoBlock) + 4];
	struct  FileInfoBlock *Ifib;
	int	i;
	char	*s, *path;

	Ifib  = (struct FileInfoBlock *) BufRound(Ibuf);
	if (!Examine(curlock, Ifib)) return(0);
	/* if (!IsDir(Ifib)) return(0); */
	/*
	 * find full path name; build LIFO stack of
	 * pushed locks; when full use popped locks with
	 * Examine() to get each name in path.
	 */
	for (i=0; i<LOCKSTACKSIZE; i++) {
		locklist[i] = curlock;
		if (!(curlock = ParentDir(curlock)) )
			break; 	/* normal loop exit */
	}
	path = &pathbuf[0];
	if (i >= LOCKSTACKSIZE) {
		err("Too many subdirectories");
		*path++ = '?';
		*path++ = '/';
		--i;
	}
	/*
	 * concatenate each component of path
	 */
	if (!Examine(locklist[i--], Ifib))
		goto wierd;
	for (s=Ifib->fib_FileName; *s; )
		*path++ = *s++;
	*path++ = ':';
	while (i >= 0) {
		if (!Examine(locklist[i], Ifib))
			goto wierd;
		for (s=Ifib->fib_FileName; *s; )
			*path++ = *s++;
		if (i>0) *path++ = '/';
		--i;
	}
	*path = '\0';
	return(path - &pathbuf[0]);
wierd:
	*path++ = '?';
	*path++ = '/';
	*path = '\0';
	return(path - &pathbuf[0]);
} /* Lock2Path() */

/*
 * is this a directory?
 */
IsDir(Ifib)
	struct	FileInfoBlock *Ifib;
{
	if (!Ifib) return(0);
	if (Ifib->fib_DirEntryType > 0) return(1);
	return(0);
} /* IsDir() */

main(argc, argv)
	int	argc;
	char	**argv;
{
	int	type;
	char	*typename;

	if (argc != 2 || !IsDevName(argv[1])) {
		printf("Usage (e.g)-- devinfo df0:\n");
		exit(1);
	}
	type = IsDevice(argv[1]);
	printf("%s -- ", argv[1]);
	switch(type) {
	case NONE_SUCH:
		typename = "does not exist";
		break;
	case DEVICE:
		typename = "device";
		break;
	case DIRECTORY:
		typename = "directory";
		break;
	case VOLUME:
		typename = "volume";
		break;
	default:
		typename = "???";
	}
	printf(" %s ", typename);
	if (ExtraInfo)
		printf("(%s)\n", ExtraInfo);
	else
		printf("\n");
}

err(s)
	char	*s;
{
	printf("error: %s\n", s);
}
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

koren@hpfelg.HP.COM (Steve Koren) (12/14/89)

>	pr->pr_WindowPtr = -1;		/* Turn off requesters */

That was the key thing I needed to know.  Thanks.  It works, but I've
never seen it documented anyplace, so I'm a bit nervous about it.

> You don't seem to grok what Volume's are. They are basic unit of Disk, not
> the device like df0:. If I have a volume on a floppy, I don't care what 
      ....
> inserted into DF0: but generally this is useless info. Assigns, like C:,
      ....
> Is that any clearer?

Yes, I have understood the differences between volumes and devices since
around 1985, but I disagree with your comment about the status of df0:
being useless info.  If the user has included 'df0:c' in his path, I
need to bypass df0: if there is no disk inserted.  The user might well
do this instead of using the volume name to access the files in the 'c'
directory of whatever disk happens to be in df0: at the time, while c:
might point to the 'c' directory on his hard disk.

Anyhow, this new feature of ignoring offline parts of the path has been
added; it will appear in 1.3.  I also do that for some commands;  for
example, a 'cd df0:' will not produce the requester if there is no disk
in df0:.

       - steve

cmcmanis%pepper@Sun.COM (Chuck McManis) (12/15/89)

In article <13920033@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
>             ... I disagree with your comment about the status of df0:
>being useless info.  If the user has included 'df0:c' in his path, I
>need to bypass df0: if there is no disk inserted.  The user might well
>do this instead of using the volume name to access the files in the 'c'
>directory of whatever disk happens to be in df0: at the time, while c:
>might point to the 'c' directory on his hard disk.

This is an interesting semantic for path searching that I don't suspect
is intuitive. When I read this originally, I thought what you might want
to do is find out what volume was in df0:c, and store that so that if
the user had made their path df0:c;df0:tools;sys:lc;Utilities: you could
note the volume that was on df0: and not search df0:c or df0:tools when
it wasn't mounted. However, on rereading it I suspect you really want
the behaviour to be 
	if there is *any* disk in df0: and it has a c directory
	search it at this point in the path. 

At first this sounds kind of nifty since you don't care what the volume
is you can just change your path by swapping the disk in df0:. And yet,
on closer inspection, it seems that there might be massive user confusion
if they had only floppy drives and were trying to run a script that 
involved more disks then they had floppies. Let's say they have one floppy
and their script is a usenet news unpacker. Now they have a disk full of
Usenet news, and a "usenet" system disk which has on it compress, rnews
etc. Now if their path was df0:c, when they start up the script, everything
works until they have to swap the system disk with the data disk. The next
command that runs (let's further assume the script is in ram: so that they
don't have to go back to the system disk to read it.) the next command it
searches for df0:c, finds it isn't there and the script exits with command
not found. Not to friendly, and not to useful either. Something that happens
to me all of the time is that I've renamed my EMACs "ed" because I just type
ed and it gives me whatever editor I use on the system I type it on. This
works because I've deleted the CBM ed from all of my system disks. Now
if I suddenly put a fresher copy of a workbench into my drive, I would
wind up with the wrong editor. 

As I see it the Volume concept makes single drive machines possible because
you can specify the volume name and the machine will always ask you to insert
the disk if it isn't available.

This all brings up another interesting idea. Lets say you cached the names
of all the executables in a path. Now searching the path would be really
fast, and you would never look at a disk unless you needed a command from
it, and you could request disks that weren't in a drive currently to be 
loaded if you needed a command from them. Of course when the contents of 
the directories changed you would have to type rehash or something similar
to get them back into your path but csh users live with that today and it
doesn't seem to bother them.


--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@Eng.Sun.COM
These opinions are my own and no one elses, but you knew that didn't you.
"If it didn't have bones in it, it wouldn't be crunchy now would it?!"

peter@sugar.hackercorp.com (Peter da Silva) (12/15/89)

In article <5010@amiga.UUCP> kodiak@batgirl.UUCP (Robert R. Burns) writes:
> Please hack it to include a Forbid() around the manipulation of the dos
> device list, lest you find yourself holding onto an obsolete node and then
> linking off to junk.

Oops.

Sorry, Bob.
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U`  "I haven't lost my mind, it's backed up on tape somewhere"

peter@sugar.hackercorp.com (Peter da Silva) (12/15/89)

In article <13920033@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
> Anyhow, this new feature of ignoring offline parts of the path has been
> added; it will appear in 1.3.  I also do that for some commands;  for
> example, a 'cd df0:' will not produce the requester if there is no disk
> in df0:.

Could you make this settable? With default ON in interactive use and OFF
otherwise? Sometimes you want the requestor.
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U`  "I haven't lost my mind, it's backed up on tape somewhere"

koren@hpfelg.HP.COM (Steve Koren) (12/18/89)

> This all brings up another interesting idea. Lets say you cached the names
> of all the executables in a path. Now searching the path would be really
> fast, and you would never look at a disk unless you needed a command from

Yeah, I think csh (Un*x) does that.  I might do it evenentually, but there's
a bunch of issues to be worked out first.

Also, Peter writes (re: bypassing disk requesters):

> Could you make this settable? With default ON in interactive use and OFF
> otherwise? Sometimes you want the requestor.

I think so.  That's a good idea, and should be easy to do.

          - steve

peter@sugar.hackercorp.com (Peter da Silva) (12/19/89)

In article <13920034@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
> Also, Peter writes (re: bypassing disk requesters):

> > Could you make this settable? With default ON in interactive use and OFF
> > otherwise? Sometimes you want the requestor.

> I think so.  That's a good idea, and should be easy to do.

Another thing: how about going back and checking the unmounted volumes with
requestors ON if you don't find the command in any of the mounted components
of your PATH?

(and how about allowing wildcards on volume names, huh?)
-- 
Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com>
`-_-'
 'U`  "I haven't lost my mind, it's backed up on tape somewhere"

kim@uts.amdahl.com (Kim DeVaughn) (12/20/89)

In article <4797@sugar.hackercorp.com>, peter@sugar.hackercorp.com (Peter da Silva) writes:
> In article <13920034@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes:
> > Also, Peter writes (re: bypassing disk requesters):
> 
> > > Could you make this settable? With default ON in interactive use and OFF
> > > otherwise? Sometimes you want the requestor.
> 
> > I think so.  That's a good idea, and should be easy to do.
> 
> Another thing: how about going back and checking the unmounted volumes with
> requestors ON if you don't find the command in any of the mounted components
> of your PATH?

If you do this, could you make this settable?  With default either way.  Some
people don't want requesters at all.

/kim
-- 
UUCP:  kim@amdahl.amdahl.com
  or:  {sun,decwrl,hplabs,pyramid,uunet,oliveb,ames}!amdahl!kim
DDD:   408-746-8462
USPS:  Amdahl Corp.  M/S 249,  1250 E. Arques Av,  Sunnyvale, CA 94086
BIX:   kdevaughn     GEnie:   K.DEVAUGHN     CIS:   76535,25

koren@hpfelg.HP.COM (Steve Koren) (01/03/90)

I have a question about the console device:

The Amiga console device normally blocks programs from outputting text
if you have typed characters from the keyboard that have not yet been
read.  For example, I can type

  my_prog

which outputs some stuff, and if I type some characters while my_prog
is loading, my_prog will produce no output until I press return.

I want to be able to convince the console that its OK for my_prog to
output some characters.  I wish to use this for SKsh; for example, you
type a command, and just before the Sksh prompt appears you type
another.  Currently, SKsh won't display the prompt while you type the
second command, since the console is stopping it from doing so.  Does
anyone know how I can fix this?  Something like ProdConsoleDevice()
would be what I need.

    thanks, any help will be appriciated!

         -steve (koren@hpfela.HP.COM)

jac@muslix.llnl.gov (James Crotinger) (01/05/90)

  Does Sksh use ConMan? One of the conman devices (used to be cnd:, but
I think 1.3c calls it cnn:) does non-blocking type-ahead. Lots of VMS 
users asked for this, and I really like it. Does the real ksh do this?
I may just have to give it a try. Anyway, cnn: allows you to type ahead
whilee the text is scrolling. The text you type will show up the next time
the console is ready to read. However if the program throws the console
into raw mode you lose what you typed. 

  Jim

koren@hpfelg.HP.COM (Steve Koren) (01/08/90)

>   Does Sksh use ConMan? One of the conman devices (used to be cnd:, but
> I think 1.3c calls it cnn:) does non-blocking type-ahead. Lots of VMS 

No, right now it simply uses the AmigaDos console device and sends ANSI
codes to it.  Does ConMan support ANSI control codes?

I'd prefer to obtain the desired non-blocking behavior with the AmigaDos
console device.  I'm trying to keep SKsh as independent as possible of
non-AmigaDos software.  I already depend on ARP for binary execution (since
there was no reliable way to accomplish this in AmigaDos), so even now
SKsh cannot be used on a stock Amiga until the user finds ARP.
There has been alot of confusion from people who have a really old arp
and try to use SKsh.  If 1.4 brings a way to execute external binaries
reliably, I will remove the ARP dependency from SKsh.  There is nothing
wrong with ARP, but using it means that 1) SKsh will break if ARP goes
away or breaks, 2) SKsh will break if user's have an old version of ARP,
and 3) users must know how where to get ARP.

> users asked for this, and I really like it. Does the real ksh do this?

Yes, the real ksh does this (at least on some systems).  I like it too.

> the console is ready to read. However if the program throws the console
> into raw mode you lose what you typed. 

Right now, SKsh does put the console in raw mode sometimes.  It has to
in order to accomplish the command line editing functions.

So, does anyone know how to accomplish non-blocking input with the
normal AmigaDos console device?

  thanks,

     - steve